The below question relates to the following sections in the React Context documentation:
Disclaimer: Apologies for all the background information below. It provides context and will hopefully be helpful to future visitors.
What We Know
themes.dark (an object that contains two properties: foreground and background)Providers above the Consumer in the component treeProvider present in the top-level component (App)Provider (App), passes down its own state as the context valueProvider equal in structure and type to the default context value (avoids Consumers getting confused)state in the top-level component (App) holds an object of the same format as the default context value: themes.lightConsumer reads the context, it reads App's stateApp) state deep down in the component tree, without having to pass it through every component in the middleApp) changes, it re-renders and a new value for state is provided to the ConsumerConsumer reads the parent's state, via contextstate (toggleTheme) is passed down the component tree as a normal propcontext only contains an object that reads stateConsumer by passing the setState function as a normal prop from the Provider's child, down through all the intermediate components, and in to the Consumerstate in the top-level component (App), leads to a re-render of itself, which leads to a re-render of the Provider, which then passes the new App state value down to its Consumer via contextConsumer always knows App's state, via contextstate is provided as context value to child Consumer(s)state is updated by some childProvider sees that context value (App's state) has changed, and re-renders all its Consumers with the new valuestate in the Consumer, by passing the setState function within the contextprop to set stateQuestions
We know from the docs that:
Every Context object comes with a Provider React component that allows consuming components to subscribe to context changes....
All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.
App as the context value. We know from the above quote that changing it leads to the Provider re-rendering. Why then, do we bother using state as the context value? What is the benefit of that, vs. just using any normal variable in App?state. Why is link 2 incorporating the function to update state within state itself? Could we not just have it as a separate setState function, which is passed to the Consumer via context in an object that has two properties (one is state and the other is the standalone function to update state)?Let's assume we use a normal variable in App as the context value. We know from the above quote that changing it leads to the Provider re-rendering. Why then, do we bother using state as the context value? What is the benefit of that, vs. just using any normal variable in App?
It's true that when the provider is rerendered with a changed value, any descendents that care about the context will rerender. But you need something to cause the provider to rerender in the first place. This will happen when App's state or its props change (or when you call forceUpdate, but don't do that). Presumably, this is at the top of your application, so there are no props coming in, which means you'll use state to cause it to rerender.
Both the two approaches above allow us to update state. Why is link 2 incorporating the function to update state within state itself? Could we not just have it as a separate setState function, which is passed to the Consumer via context in an object that has two properties (one is state and the other is the standalone function to update state)?
When deciding whether to rerender descendants due to a change of context, react will do basically a === between the old value and the new value. This is super quick and works well with React's preference for immutable data, but when using objects as your value you need to be careful that you're not making new objects on every render. For example, if App is doing something like the following, it will be creating a brand new object every time it renders, and thus will be forcing all the context consumers to rerender as well:
class App extends Component {
state = {
data: {
hello: 'world',
}
}
updateData() {
// some function for updating the state
}
render() {
return (
<MyContext.Provider value={{
data: this.state.data,
updateData: this.updateData
}} />
)
}
}
So the example where they store the function in state is to make sure that the entire value they're providing does not change from one render to another.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With