DEV Community

Cover image for 🔺 Flat React Doom Pyramid in 1LOC
Andrei Luca
Andrei Luca

Posted on • Updated on

🔺 Flat React Doom Pyramid in 1LOC

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>
Enter fullscreen mode Exit fullscreen mode

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 }}));
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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)}</>;
}
Enter fullscreen mode Exit fullscreen mode

And the usage will be like this:

<Flatten
  elements={[
    <I18nProvider />,
    <DataProvider />,
    <ActiveDialogProvider />,
    <PublicFetchProvider />,
    <AuthProvider />,
    <PrivateFetchProvider />,
    <AuthFetchProvider />,
    <CustomThemeProvider />,
    <CustomMuiPickersUtilsProvider />,
    <LegalsProvider />,
    <PaymentMethodsProvider />,
    <CartProvider />,
  ]}>
  <App />
</Flatten>
Enter fullscreen mode Exit fullscreen mode

I went through multiple iterations, and in the end I prefer first Pipe one liner that I showed.

Sandboxes experiments:

Thanks for coming to my TED talk! :)

Cover Photo by Kévin et Laurianne Langlais on Unsplash

Top comments (10)

Collapse
 
teetotum profile image
Martin • Edited

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.

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
ygormartins profile image
Ygor Martins

Agreed! The first approach can be pretty confusing and overwhelming to look at

Collapse
 
iamandrewluca profile image
Andrei Luca

Now I also agree. Looking at first version looks confusing.

Collapse
 
gillarohith profile image
Rohith Gilla

Haha good one

Collapse
 
donkarolel profile image
Karolis Juškauskas

Great idea, however, what if you moved all of the providers to the Pipe component?

Collapse
 
iamandrewluca profile image
Andrei Luca

Can you please elaborate? 🤔 That was the point. You write the code flat, and the Pipe will make them in a pyramid shape automatically

Collapse
 
donkarolel profile image
Karolis Juškauskas

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>.

Thread Thread
 
iamandrewluca profile image
Andrei Luca

Yeap

Thread Thread
 
donkarolel profile image
Karolis Juškauskas

Neat.