Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to combo multiple ContextProvider #14520

Closed
hangyangws opened this issue Jan 2, 2019 · 4 comments
Closed

How to combo multiple ContextProvider #14520

hangyangws opened this issue Jan 2, 2019 · 4 comments

Comments

@hangyangws
Copy link

hangyangws commented Jan 2, 2019

I learn the Hooks,it's so good!
Bug when I use hooks: useReducer。I confused by multiple provider.

my simple files

  1. app.js:
import Provider from './store/index.js';

ReactDOM.render(
  <Provider>
    <Router history={history}>
      <Layout>
        <Switch>
          <Route ... />
        </Switch>
      </Layout>
    </Router>
  </Provider>,
  CONTAINER
);
  1. ./store/index.js
import providerOne from './providerOne.js';
import ProviderTwo from './providerTwo.js';
import ProviderThree from './providerThree.js';
// there maybe have many providers...

return (
  <ProviderOne>
    <ProviderTwo>
      <ProviderThree>
        {props.children}
      </ProviderThree>
    </ProviderTwo>
  </ProviderOne>
);
  1. ./store/providerOne.js
const Context = React.createContext();

const initState = [];
const reducer = (state, action) => {
  switch (action.type) {
    case 'xxx':
      return xxx;
    default:
      return state;
  }
};

const ProviderOne = (props) => {
  const [state, dispatch] = React.useReducer(reducer, initState);

  return <Context.Provider value={{ state, dispatch }}>{props.children}</Context.Provider>;
};

export default ProviderOne;

my confusion

In file ./store/index.js, I must write many times <Provider> structure.
There is any way to solve it.

@tmenyhart
Copy link

Hey @hangyangws , I was just thinking about the same problem, and I've found the solution for this in this repo: https://github.com/FormidableLabs/react-context-composer

This solution was fine for me, hope it helps you too.

Simply put, if you want to get rid of the deep nesting of context providers you can write a util functional component like this:

export const ContextProviderComposer = ({contextProviders, children}) => {
  return contextProviders.reduceRight((children, parent, index) => React.cloneElement(parent, { children }), children);
};

ContextProviderComposer.propTypes = {
  contextProviders: PropTypes.arrayOf(
    PropTypes.element,
  ).isRequired,
  children: PropTypes.node.isRequired,
};

And you can use it in a component by listing your context providers:

import providerOne from './providerOne.js';
import ProviderTwo from './providerTwo.js';
import ProviderThree from './providerThree.js';

return (
  <ContextProviderComposer contextProviders={[
    <ProviderOne key={0}/>
    <ProviderTwo key={1}/>
    <ProviderThree key={2}/>
  ]}>
    { props.children }
  </ContextProviderComposer>
);

@aweary
Copy link
Contributor

aweary commented Jan 5, 2019

We use the issue tracker for bug reports and feature requests.

If you have a question, please check our community support resources:
https://facebook.github.io/react/community/support.html

@csr632
Copy link

csr632 commented Mar 16, 2020

I have created another state management library that is better at service composition. Here is a demo of avoiding provider hell. Feel free to try it or read its source(100 lines of code)!

@nanxiaobei
Copy link

nanxiaobei commented Jun 7, 2021

react-easy-contexts, A simple tool to add multiple React contexts easily.

https://github.com/nanxiaobei/react-easy-contexts

import { create, useProvider } from 'react-easy-contexts';

const ctx = create({
  useX() {
    const [x, setX] = useState(0);
    return useMemo(() => ({ x, setX }), [x]);
  },
  useY() {
    const [y, setY] = useState(0);
    return useMemo(() => ({ y, setY }), [y]);
  },
  useZ() {
    const [z, setZ] = useState(0);
    return useMemo(() => ({ z, setZ }), [z]);
  },
});

const App = () => {
  const Provider = useProvider(ctx);
  return (
    <Provider>
      <AppMain />
    </Provider>
  );
};

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

No branches or pull requests

5 participants