How to use React Hooks Context with multiple values for Providers
The main consideration (from a performance standpoint) for what to group together is less about which ones are used together and more about which ones change together. For things that are mostly set into context once (or at least very infrequently), you can probably keep them all together without any issue. But if there are some things mixed in that change much more frequently, it may be worth separating them out.
For instance, I would expect deviceTheme
to be fairly static for a given user and probably used by a large number of components. I would guess that popup
might be managing something about whether you currently have a popup window open, so it probably changes with every action related to opening/closing popups. If popup
and deviceTheme
are bundled in the same context, then every time popup
changes it will cause all the components dependent on deviceTheme
to also re-render. So I would probably have a separate PopupContext
. windowSize
and windowScroll
would likely have similar issues. What exact approach to use gets deeper into opinion-land, but you could have an AppContext
for the infrequently changing pieces and then more specific contexts for things that change more often.
The following CodeSandbox provides a demonstration of the interaction between useState and useContext with context divided a few different ways and some buttons to update the state that is held in context.
You can go to this URL to view the result in a full browser window. I encourage you to first get a handle for how the result works and then look at the code and experiment with it if there are other scenarios you want to understand.
This answer already does a good job at explaining how the context can be structured to be more efficient. But the final goal is to make context consumers be updated only when needed. It depends on specific case whether it's preferable to have single or multiple contexts.
At this point the problem is common for most global state React implementations, e.g. Redux. And a common solution is to make consumer components update only when needed with React.PureComponent
, React.memo
or shouldComponentUpdate
hook:
const SomeComponent = memo(({ theme }) => <div>{theme}</div>);
...
<AllContext>
{({ deviceTheme }) => <SomeComponent theme={deviceTheme}/>
</AllContext>
SomeComponent
will be re-rendered only on deviceTheme
updates, even if the context or parent component is updated. This may or may not be desirable.