Skip to content

Instantly share code, notes, and snippets.

@danieldogeanu
Forked from m5r/combine-provider.tsx
Last active July 30, 2023 21:32
Show Gist options
  • Select an option

  • Save danieldogeanu/cb114964d3d5a59127c4c7f3c03d4dd1 to your computer and use it in GitHub Desktop.

Select an option

Save danieldogeanu/cb114964d3d5a59127c4c7f3c03d4dd1 to your computer and use it in GitHub Desktop.

Revisions

  1. danieldogeanu revised this gist Oct 10, 2022. 2 changed files with 35 additions and 12 deletions.
    41 changes: 32 additions & 9 deletions combine-provider.tsx
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,32 @@
    import type { FunctionComponent } from "react";

    export const combineProviders = (providers: FunctionComponent[]) => providers.reduce(
    (Combined, Provider) => ({ children }) => (
    <Combined>
    <Provider>{children}</Provider>
    </Combined>
    ),
    );
    import { ComponentProps, FC, Fragment } from "react";

    export interface ProvidersProps {
    children: React.ReactNode;
    }

    export type ProviderWithProps = [FC<ProvidersProps>, Object];

    /**
    * Function that combines all the context providers into a single one.
    * @param providers Array of tuples with Provider and props pairs.
    * @returns Returns the combined providers.
    */
    export function combineProviders(providers: ProviderWithProps[]): FC<ProvidersProps> {

    // We need to use regular named functions, and not arrow functions because otherwise
    // ESLint will scream at us that the "Component definition is missing display name (react/display-name)".

    function reducer(CombinedProviders: FC<ProvidersProps>, [CurrentProvider, props = {}]: ProviderWithProps) {
    return function combiner({children}: ComponentProps<FC<ProvidersProps>>): JSX.Element {
    return <CombinedProviders><CurrentProvider {...props}>{children}</CurrentProvider></CombinedProviders>;
    };
    }

    // We also need to provide an initial value for the reducer.

    function initialValue({children}: ComponentProps<FC<ProvidersProps>>): JSX.Element {
    return <Fragment>{children}</Fragment>;
    }

    return providers.reduce(reducer, initialValue);
    }
    6 changes: 3 additions & 3 deletions usage.tsx
    Original file line number Diff line number Diff line change
    @@ -5,9 +5,9 @@ import { ApolloProvider } from "@apollo/client";
    import { combineProviders } from "./combine-provider";

    const Providers = combineProviders([
    BrowserRouter,
    RecoilRoot,
    ApolloProvider,
    [BrowserRouter, { basename: 'optionalString', forceRefresh: true }],
    [RecoilRoot, { initializeState: (MutableSnapshot => void), override: false }],
    [ApolloProvider, { client } ],
    ]);

    function Root() {
  2. @m5r m5r revised this gist Dec 4, 2021. No changes.
  3. @m5r m5r created this gist Dec 4, 2021.
    9 changes: 9 additions & 0 deletions combine-provider.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    import type { FunctionComponent } from "react";

    export const combineProviders = (providers: FunctionComponent[]) => providers.reduce(
    (Combined, Provider) => ({ children }) => (
    <Combined>
    <Provider>{children}</Provider>
    </Combined>
    ),
    );
    19 changes: 19 additions & 0 deletions usage.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    import { BrowserRouter } from "react-router-dom";
    import { RecoilRoot } from "recoil";
    import { ApolloProvider } from "@apollo/client";

    import { combineProviders } from "./combine-provider";

    const Providers = combineProviders([
    BrowserRouter,
    RecoilRoot,
    ApolloProvider,
    ]);

    function Root() {
    return (
    <Providers>
    <App />
    </Providers>
    );
    }