I’m working on a React application where I need to provide multiple context providers, such as I18nextProvider, HelmetProvider, BrowserRouter, Provider from Redux, and IntercomProvider. However, nesting these providers within each other, as shown in the code snippet below, can lead to messy and hard-to-maintain code:
<I18nextProvider i18n={i18n}>
<StrictMode>
<HelmetProvider>
<BrowserRouter>
<Provider store={store}>
<IntercomProvider appId={CONFIG.INTERCOM_APP_ID}>
<App />
</IntercomProvider>
</Provider>
</BrowserRouter>
</HelmetProvider>
</StrictMode>
</I18nextProvider>
>Solution :
Others have also faced this problem before. In fact, a huge GH thread exists on the React Repo.
One of the more simpler answers I found from it is using some array manipulation and taking advantage of React Composition.
const compose = (contexts, children) =>
contexts.reduce((acc, [Context, value]) => {
return <Context.Provider value={value}>{acc}</Context.Provider>;
}, children);
import Context1 from './context1';
import Context2 from './context2';
import Context3 from './context3';
...
import Context15 from './context15';
const MyComponent = (props) => {
// const value1..15 = ... get the values from somewhere ;
return compose(
[
[Context1, value1],
[Context2, value2],
[Context3, value3],
...
[Context15, value15],
],
<SomeSubComponent/>
);
}
The React team recommends rechecking the architecture if we face something like this, but I have myself seen this in code repos and am not sure what architecture change would have helped.
PS: It has never been a problem worth solving to me. The nesting is not as unreadable as callback hell. Avoiding the above code is like avoiding JSX code in any other React component, isn’t it 😛 You will merge some of the JSX and logic into another component and pull it out of your nested JSX tree, so same you could have done here also.