New to react here and trying to wrap my head round the new Context API (I haven\'t looked into Redux etc. yet).
Seems I can do much of what I need to do, but I\'m going
One simple solution for this is to use something similar to compose function in https://github.com/reduxjs/redux/blob/master/src/compose.js and combine all the providers together.
provider.js
const Providers = compose(
AuthProvider,
ThemeProvider,
ChatProvider
);
also I haven't used this solution but with React's new hooks feature, instead of rendering your contexts, you can use the react hook to access it in the function definition.
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>
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.
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)
}
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.