I have inherited a codebase where the previous owner has made extensive use of React.Context. This has resulted in what might be described as "context hell"
<AppContextProvider>
<AnotherProvider>
<AgainAnotherProvider configProp={false}>
<TestProvider>
<FooProvider>
<BarProvider configHereAlso={someEnvronmentVar}>
<BazProvider>
<BatProvider>
<App />
</BatProvider>
</BazProvider>
</BarProvider>
</FooProvider>
</TestProvider>
</AgainAnotherProvider>
</AnotherProvider>
</AppContextProvider>;
This feels like an anti-pattern and is causing considerable cognitive overhead in understanding how the whole application works.
How do I fix this? Is it possible to use just one provider for everything? I previously used redux-toolkit with redux for managing state in react. Is there anything similar for contexts?
I found an elegant solution:
const Providers = ({providers, children}) => {
const renderProvider = (providers, children) => {
const [provider, ...restProviders] = providers;
if (provider) {
return React.cloneElement(
provider,
null,
renderProvider(restProviders, children)
)
}
return children;
}
return renderProvider(providers, children)
}
ReactDOM.render(
<Providers providers={[
<FooContext.Provider value="foo" />,
<BarContext.Provider value="bar" />,
<BazContext.Provider value="baz" />,
]}>
<App />
</Providers>,
document.getElementById('root')
);
One way to get rid of additional contexts is by adding more variables to the value that is provided by a context.
For example if there are two contexts UserContext
and ProfileContext
with providers like:
<UserContext.Provider value={user}...
and
<ProfileContext.Provider value={profile}...
then you can merge them into a single context:
<UserProfileContext.Provider value={{user, profile}}...
Note: This doesn't mean you should merge all contexts into a single context because of the separation of concerns and all consumers rerender when a context's value changes leading to unwanted renders.
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