Web Totals
React Provider Hell

React Provider Hell

React Provider Hell

#Issue

const context1 = createContext({});
const context2 = createContext({});
const context3 = createContext({});
const context4 = createContext({});

const ChildApp = () => {
  const v1 = useContext(context1);
  const v2 = useContext(context2);
  const v3 = useContext(context3);
  const v4 = useContext(context4);

  return (
    <>
      <h2>ChildApp</h2>
      {v1.v}
      {v2.v}
      {v3.v}
      {v4.v}
    </>
  );
};

const App = () => {
  return (
    <>
      <context1.Provider value={{ v: 1 }}>
        <context2.Provider value={{ v: 2 }}>
          <context3.Provider value={{ v: 3 }}>
            <context4.Provider value={{ v: 4 }}>
              <ChildApp />
            </context4.Provider>
          </context3.Provider>
        </context2.Provider>
      </context1.Provider>
    </>
  );
};

render(<App />);
jsx

#Solution

const context1 = createContext({});
const context2 = createContext({});
const context3 = createContext({});
const context4 = createContext({});

const ChildApp = () => {
  const v1 = useContext(context1);
  const v2 = useContext(context2);
  const v3 = useContext(context3);
  const v4 = useContext(context4);

  return (
    <>
      <h2>ChildApp</h2>
      {v1.v}
      {v2.v}
      {v3.v}
      {v4.v}
    </>
  );
};

import { cloneElement, memo } from 'react';

export interface ContextComposeProviderProps extends React.PropsWithChildren {
  contexts: React.ReactElement[]
}

export const ComposeContextProvider = memo(({
  contexts,
  children
}: ContextComposeProviderProps) => contexts.reduceRight<React.ReactNode>(
  (children: React.ReactNode, parent) => cloneElement(
    parent,
    { children }
  ),
  children
));

const contexts = [
   context1.Provider value={{ v: 1 }} />,
  <context2.Provider value={{ v: 2 }} />,
  <context3.Provider value={{ v: 3 }} />,
  <context4.Provider value={{ v: 4 }} />,
];

const App = () => {
  return (
    <>
      <ComposeContextProvider contexts={contexts}>
        <ChildApp />
      </ComposeContextProvider>
    </>
  );
};
jsx

#Demo

stackblitz