Everyone was happy when React Team announced the new stable Context API, and everyone ditched Redux. But that's not the point.
After 1 year every codebase entrypoint looked like this at least.
<I18nProvider>
<DataProvider>
<ActiveDialogProvider>
<PublicFetchProvider>
<AuthProvider>
<PrivateFetchProvider>
<AuthFetchProvider>
<CustomThemeProvider>
<CustomMuiPickersUtilsProvider>
<LegalsProvider>
<PaymentMethodsProvider>
<CartProvider>
<App />
</CartProvider>
</PaymentMethodsProvider>
</LegalsProvider>
</CustomMuiPickersUtilsProvider>
</CustomThemeProvider>
</AuthFetchProvider>
</PrivateFetchProvider>
</AuthProvider>
</PublicFetchProvider>
</ActiveDialogProvider>
</DataProvider>
</I18nProvider>
Soooo, should we do something about this? Most of the times there is no reason. Nevertheless, here is a simple performant solution in 1 line of code
const Pipe = (p) => p.children.reduceRight((c, e) => ({ ...e, props: { ...e.props, children: c }}));
You can name it however you want:
- Flatten
- Compose
- Pipe
- Squash
- Doom 😂
- Nest
- Inflate
And how will look above example? Better!
<Pipe>
<I18nProvider />
<DataProvider />
<ActiveDialogProvider />
<PublicFetchProvider />
<AuthProvider />
<PrivateFetchProvider />
<AuthFetchProvider />
<CustomThemeProvider />
<CustomMuiPickersUtilsProvider />
<LegalsProvider />
<PaymentMethodsProvider />
<CartProvider />
<App />
</Pipe>
This function component takes all its children and nests them from first to last, where first one will be the most outside the tree, and the last one will be last in the tree.
Here is one more variation with TypeScript and different API
function Flatten(props: PropsWithChildren<{ elements: ReactElement[] }>) {
const { elements: e, children: init } = props;
return <>{e.reduceRight((c, e) => cloneElement(e, { children: c }), init)}</>;
}
And the usage will be like this:
<Flatten
elements={[
<I18nProvider />,
<DataProvider />,
<ActiveDialogProvider />,
<PublicFetchProvider />,
<AuthProvider />,
<PrivateFetchProvider />,
<AuthFetchProvider />,
<CustomThemeProvider />,
<CustomMuiPickersUtilsProvider />,
<LegalsProvider />,
<PaymentMethodsProvider />,
<CartProvider />,
]}>
<App />
</Flatten>
I went through multiple iterations, and in the end I prefer first Pipe
one liner that I showed.
Sandboxes experiments:
- https://codesandbox.io/s/react-flatten-pyramid-wpr7o
- https://codesandbox.io/s/react-flatten-pyramid-benchs-wgyhf
- https://codesandbox.io/s/react-flatten-pyramid-benchs-clean-o82xw
Thanks for coming to my TED talk! :)
Cover Photo by Kévin et Laurianne Langlais on Unsplash
Top comments (10)
Interesting approach. Never occurred to me to try such an angle.
After careful consideration I would still refrain from using it in any actual project.
The nesting as it appears to the developer when viewing the jsx source code should not -in such an unexpected way- differ from the actual nesting during runtime.
Code should be as easy to understand as possible, as clear as possible, and as un-confusing as possible.
With this approach it could easily happen that someone gets the order wrong. Or thinks the elements are siblings, when they are not.
But kudos for a clever idea and novel approach.
And lastly, the projects I work with do not really require that many providers.
Agreed! The first approach can be pretty confusing and overwhelming to look at
Now I also agree. Looking at first version looks confusing.
Haha good one
Great idea, however, what if you moved all of the providers to the Pipe component?
Can you please elaborate? 🤔 That was the point. You write the code flat, and the Pipe will make them in a pyramid shape automatically
You could have all of the providers inside of the, say, Pipe component and then you could do just something like this:
<Pipe><App/></Pipe>
.Yeap
Neat.