Too many React Context providers
Use @rista404's answer - https://stackoverflow.com/a/58924810/4035
as react-context-composer
is deprecated.
Thanks @AO17, for the ping.
Disclaimer: I've never used this, just researched.
FormidableLabs (they contribute to many OSS projects) has a project called, react-context-composer
It seems to solve your issue.
React is proposing a new Context API. The API encourages composing. This utility component helps keep your code clean when your component will be rendering multiple Context Providers and Consumers.
If you want a solution for composing Providers without any third-party libraries, here's one with Typescript annotations:
// Compose.tsx
interface Props {
components: Array<React.JSXElementConstructor<React.PropsWithChildren<any>>>
children: React.ReactNode
}
export default function Compose(props: Props) {
const { components = [], children } = props
return (
<>
{components.reduceRight((acc, Comp) => {
return <Comp>{acc}</Comp>
}, children)}
</>
)
}
Usage:
<Compose components={[BrowserRouter, AuthProvider, ThemeProvider, ChatProvider]}>
<App />
</Compose>
You can of course remove the annotations if you don't use Typescript.
Solution with for
loop:
export const provider = (provider, props = {}) => [provider, props];
export const ProviderComposer = ({providers, children}) => {
for (let i = providers.length - 1; i >= 0; --i) {
const [Provider, props] = providers[i];
children = <Provider {...props}>{children}</Provider>
}
return children;
}
Usage:
<ProviderComposer
providers={[
provider(AuthProvider),
provider(ThemeProvider),
provider(MuiPickersUtilsProvider, {utils: DateFnsUtils}),
]}
>
<App/>
</ProviderComposer>
Few lines of code solve your problem.
import React from "react"
import _ from "lodash"
/**
* Provided that a list of providers [P1, P2, P3, P4] is passed as props,
* it renders
*
* <P1>
<P2>
<P3>
<P4>
{children}
</P4>
</P3>
</P2>
</P1>
*
*/
export default function ComposeProviders({ Providers, children }) {
if (_.isEmpty(Providers)) return children
return _.reverse(Providers)
.reduce((acc, Provider) => {
return <Provider>{acc}</Provider>
}, children)
}