問題描述
React Context 是道具鑽探的解毒劑嗎? (Is React Context an antidote for prop drilling?)
如果 React Context API 旨在用於傳遞全局變量,我們為什麼要使用它們來代替從父組件到子組件的傳遞道具(道具鑽探)?由於大多數傳遞的道具並不意味著在應用程序範圍內可用,即全局可用。
參考解法
方法 1:
The new react context api allows you to "scope" the values, you don't have to wrap your whole application with the context provider, you can only wrap the part of the component tree where you need particular props. It can be useful when your component tree is deeply nested and you'd need to pass certain props multiple levels.
方法 2:
The variables or values defined in context are available to any component that tries to destructure those values. However, if you have any setters that change those defined values, only the children that are passed to the Provider
will get the updated values.
For instance, if we create a context myContext
and define name
and age
, we have to then set up a provider that will provide it's children that information to consume.
const myContext = createContext({
name: 'Bob',
age: 35
});
Now, we can use a Provider to pass that data down to children.
function HelloWorld() {
const { Provider } = myContext;
const [age, setAge] = useState(35)
const [name, setName] = useState('Bob')
return (
<Provider value={{ name, age }}>
<Profile />
</Provider>
)
}
name
and age
are the values we want to expose to our children, in this case we just have one child Profile
. Now we can access name
and age
in Profile
by destructuring them from our context.
function Profile(){
const { name, age } = useContext(myContext)
return (
<ul>
<li>{name}</li>
<li>{age}</li>
</ul>
)
}
But let's say somewhere else in our project we have component called Foo
and we want to access name
.
function Foo() {
const { name } = useContext(myContext) // you will only receive the default values defined in context
return <p>{name}</p>
}
This will return the default 'Bob' defined in myContext
. You may think, what was the point of that?
If we update our HelloWorld
component to actually update the name
and age
onMount, Foo
will still show Bob
.
function HelloWorld() {
const { Provider } = myContext;
const [age, setAge] = useState("");
const [name, setName] = useState("");
useEffect(() => {
setAge(40);
setName("Bill");
}, []);
return (
<Provider value={{ name, age }}>
<Profile />
</Provider>
);
}
function Profile() {
return (
<ul>
<li>{name}</li> // returns Bill
<li>{age}</li> // returns 40
</ul>
)
}
function Foo() {
return (
<p>{name}</p> // returns Bob
)
}
This is great when you have isolated features or components that need to pass around data and setters instead of prop drilling. You can have a component consume multiple contexts and you can have as many contexts as you want as long as they make sense. If you are passing a prop down just once, does not make sense to use context. If you have more complex passing of props, context may be worth it.
(by Future Man、Krzysztof Woliński、Bens Steves)