We are running off the assumption that creating context as class components prevents unneccessary re-renders. One of those unneccessary re-renders was assumed to be the case where a child component only uses one value from state and should not rerender when state values it does not use is changed.
This is not the case. Changing any part of the state in a context causes a re-render of any child component using that state, no matter whether the context component is created as a class or function.
This is an old issue with much discussion:
Provide more ways to bail out inside Hooks #14110
This issue comment provides three ways to work around it:
Preventing rerenders with React.memo and useContext hook. #15156
I've created a demo app that demonstrates how both forms of a Context component cause the same re-renders and also how the useMemo
solution works for either one.
This solution isn't really feasible for RBS so the first option listed of splitting contexts that aren't related is probably the way to go. We do this, but this just affirms that.
The Provider component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers. Providers can be nested to override values deeper within the tree.
All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes. The propagation from Provider to its descendant consumers (including .contextType and useContext) is not subject to the shouldComponentUpdate method, so the consumer is updated even when an ancestor component skips an update.
Changes are determined by comparing the new and old values using the same algorithm as Object.is.