Skip to content

Instantly share code, notes, and snippets.

@thebinaryfelix
Last active May 30, 2024 13:34
Show Gist options
  • Save thebinaryfelix/6f85a9ec7cad11accb71f22d8e2edfec to your computer and use it in GitHub Desktop.
Save thebinaryfelix/6f85a9ec7cad11accb71f22d8e2edfec to your computer and use it in GitHub Desktop.
Component for composing providers in React v18 with Typescript
export interface IProviderComposerProps extends React.PropsWithChildren {
/**
* Providers list
* */
with: React.FC<React.PropsWithChildren>[]
}
const ComposerFragment: React.FC<React.PropsWithChildren> = ({
children,
}): JSX.Element => <>{children}</>
const providerReducer =
(
ParentProvider: React.FC<React.PropsWithChildren>,
ChildProvider: React.FC<React.PropsWithChildren>,
) =>
({ children }: React.PropsWithChildren) =>
(
<ParentProvider>
<ChildProvider>{children}</ChildProvider>
</ParentProvider>
)
/**
* @Component
* @name ProviderComposer
* @description Component that receives a list of providers and composes them to a single component.
*/
export const ProviderComposer = (props: IProviderComposerProps) => {
const ComposedProviders = props.with.reduce(providerReducer, ComposerFragment)
return <ComposedProviders>{props.children}</ComposedProviders>
}
@thebinaryfelix
Copy link
Author

thebinaryfelix commented Oct 30, 2022

How to use

Instead of nesting providers like this:

<FirstProvider>
  <SecondProvider>
    <ThirdProvider>
      {children}
    </ThirdProvider>
  </SecondProvider>
</FirstProvider>

Use the ProviderComposer to make it cleaner:

<ProviderComposer
  with={[
    FirstProvider,
    SecondProvider,
    ThirdProvider
  ]}
>
  {children}
</ProviderComposer>

@carlosrziegler
Copy link

Nice, but how can I put some providers that has props ?
<MantineProvider theme={{ primaryColor: 'blue', fontFamily: 'Inter VP' }} withGlobalStyles withNormalizeCSS withCSSVariables > ?

@thebinaryfelix
Copy link
Author

thebinaryfelix commented Nov 9, 2022

@carlosrziegler you can create a component such as:

const MyProvider = ({ children }) => (
  <MantineProvider
    theme={{ primaryColor: 'blue', fontFamily: 'Inter VP' }}
    withGlobalStyles
    withNormalizeCSS
    withCSSVariables
  >
    {children}
  </MantineProvider>)

And then use that in the ProviderComposer.

<ProviderComposer with={[MyProvider]} />

As long as your component receives children and pass it along, you can even include complex logic inside the providers.

@t1amat9409
Copy link

@thebinaryfelix do you stack them in order of dependency to each?

@thebinaryfelix
Copy link
Author

thebinaryfelix commented Nov 9, 2022

@t1amat9409 yes, because the order matters. In the example above, the FirstProvider should be placed in the first position of the array.

@t1amat9409
Copy link

@thebinaryfelix nice! this is awesome!!

@mncorreia
Copy link

🚀🚀🚀

@mmospanenko
Copy link

mmospanenko commented May 30, 2024

how to solve ESLint Component definition is missing display name?

I changed on named functions syntax for now
image

const providerReducer = (
  ParentProvider: React.FC<React.PropsWithChildren>,
  ChildProvider: React.FC<React.PropsWithChildren>,
) =>
  function providerReducerInner({ children }: React.PropsWithChildren) {
    return (
      <ParentProvider>
        <ChildProvider>{children}</ChildProvider>
      </ParentProvider>
    );
  };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment