In another StackOverflow post, Nicholas helped me understand that a Context.Provider
re-renders its descendant Context.Consumer
components when the context value the Provider
provides changes.
That is further confirmed by the official Doc:
All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.
Nicholas also helped me understand that the only way a Provider
will know if the context value has changed, is if its enclosing component re-renders.
In summary:
Providers
update its Consumers
whenever the context value changesProvider
re-rendersProvider
and all its descendants re-rendering anywaysThus, the feature in (1) above, seem redundant. If Provider
ever only updates Consumers
when its enclosing component re-renders, and spotting a context value update can only happen when the parent re-renders, there is no need to have the feature that allows the Provider
to update the Consumers
when the context value changes.
What am I missing here?
EDIT
Nicholas also says in a comment:
App can (conceivably) rerender due to things that have nothing to do the value its providing via context. If this happens, you do not want the consumers to rerender. For that to happen, you need the value before and the value after to pass a === check. If you're providing an object, that means you can't create a brand new object in App's render method, or you'll end up rerendering consumers unnecessarily.
However, I was under the impression that when a parent re-renders, all its children will also re-render. Thus, the ===
check mentioned above would not help, i.e. the children would re-render regardless.
3) Which leads to the Provider and all its descendants re-rendering anyways
While this is the default behavior, in practice it's common to change this in order to improve performance. Pure components, components that implement shouldComponentUpdate, or components using React.memo will cause the rerendering to stop before going through the entire tree.
For example: suppose there's a toplevel component with some state, which renders a midlevel component that has shouldComponentUpdate() { return false; }
, which renders a bottom level component. On the initial mount, all 3 of these will render. But then if the toplevel component updates its state, only the toplevel component will rerender. The midlevel component will be skipped due to its shouldComponentUpdate, and then the bottom level component is never even considered.
Now we add in a context provider to the toplevel component, and a context consumer to the bottom level component. On the initial mount, they will again all render. If the toplevel component updates its state, it will rerender. The midlevel component will still skip its render, due to its shouldComponentUpdate. But as long as the context value changed, the bottom level component will rerender, even though its parent bailed out. This is the feature that is referred to by that blurb.
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