-
Notifications
You must be signed in to change notification settings - Fork 46.8k
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
Suggestion: useProvider for replacing context.Provider #14534
Comments
Solution for class component: class App extends React.Component {
constructor(props) {
super(props)
this.state = {
theme: {color: 'white'},
user: {name: 'rabbit'}
}
}
static withProviders() {
const {theme, user} = this.state
return [
[themeContext, theme],
[userContext, user]
]
}
} It looks a little bit stupid but better than nested Providers. |
Providers intentionally don't work this way because the notion of tree structure actually has a meaning (unlike Hooks like |
I still think this is a valid suggestion and even considering the issue you described does not outweighs the pros in my opinion. Edit: Using a wrapper function it is possible to provide such a feature right now, but it would require always wrapping the component with withProviders when using the useProvider hook import React from "react";
let activeProviders: Map<React.Context<any>, any> | undefined;
export function withProviders<P = any>(renderFunc: (props: P) => React.ReactElement<any>) {
return (props: P) => {
const providers = activeProviders = new Map<React.Context<any>, any>();
let content = renderFunc(props);
activeProviders = undefined;
providers.forEach((v, P) => {
content = <P.Provider value={v} children={content} />;
});
return content;
}
}
export function useProvider<T>(ctx: React.Context<T>, value: T) {
if (!activeProviders)
throw new Error('withProviders wrapper required!');
activeProviders.set(ctx, value);
}
const TestContext1 = React.createContext(1);
const TestContext2 = React.createContext(2);
export const ChildCmp: React.FC = () => {
const value1 = React.useContext(TestContext1);
const value2 = React.useContext(TestContext2);
return (
<div>
<div>Child value 1 = {value1}</div>
<div>Child value 2 = {value2}</div>
</div>
)
};
export const ParentCmp: React.FC = withProviders(() => {
useProvider(TestContext1, 10);
useProvider(TestContext2, 20);
const value1 = React.useContext(TestContext1);
const value2 = React.useContext(TestContext2);
return (
<div>
<div>Value 1 = {value1}</div>
<div>Value 2 = {value2}</div>
<ChildCmp />
</div>
)
}); |
I don't understand this objection, can you speak further? It seems like a |
I have created a 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)! It introduce a "scope" object to collect the context provider, so that:
|
Yes it's not a good pattern to make provider a hook, but why not attach all the Contexts to the root element of the Component? It don't break the tree structure. Or make a multiple provider(don't use contexts.reduce inside, instead, use only one layer in the tree):
similar to
we need tree structure between context and component, but don't need that between contexts. It doesn't make a significant difference unless one use many contexts, but just looks more make sense. |
Try react-multi-provide |
is equivalent to
The text was updated successfully, but these errors were encountered: