Reactjs 是否可以使用相同的<;上下文提供程序>;在多个组件上?

Reactjs 是否可以使用相同的<;上下文提供程序>;在多个组件上?,reactjs,react-context,Reactjs,React Context,我知道我可以用包装HOC,并在所有子组件中使用它 我想在两个独立的组件中使用上下文,但它们嵌套在某个很深的地方,并且它们最接近的父组件位于应用程序根目录的某个地方。我不想为(几乎)所有组件提供上下文,所以我想知道是否可以只包装这两个组件 我试图这样做,但只有第一个组件获得上下文 应用程序结构如下所示: <App> <A1> <A2> <MyContext.Provider>

我知道我可以用
包装HOC,并在所有子组件中使用它

我想在两个独立的组件中使用上下文,但它们嵌套在某个很深的地方,并且它们最接近的父组件位于应用程序根目录的某个地方。我不想为(几乎)所有组件提供上下文,所以我想知道是否可以只包装这两个组件

我试图这样做,但只有第一个组件获得上下文

应用程序结构如下所示:

<App>
    <A1>
        <A2>
            <MyContext.Provider>
                <Consumer1/>
            </MyContext.Provider>
        </A2>
    </A1>
    <B1>
        <B2>
            <MyContext.Provider>
                <Consumer2/>
            </MyContext.Provider>
        </B2>
    </B1>
</App>



编辑:我错误地认为包装根组件将使所有子组件在上下文更改时重新呈现。只有使用者才会重新加载,因此包装根组件是完全正确的。

根据OP的要求,此解决方案主要使用挂钩,但useReducer无法在单独的提供程序下实现状态共享(就我所尝试的)

它不需要一个提供者位于应用程序的根目录,每个提供者可以使用不同的reducer

它使用一个静态状态管理器,但这是一个实现细节,要在不同上下文提供程序下的多个组件之间共享状态,需要一些东西,例如对状态的共享引用、更改状态的方法以及通知这些更改的方法

使用代码段时,第一个按钮显示共享状态,单击时递增
foo
,第二个按钮显示相同的共享状态,单击时递增
bar

//上下文
const MyContext=React.createContext();
//共享静态
类提供程序状态{
静态项=[];
静态寄存器(项){
ProviderState.items.push(项目);
}
静态注销(项目){
const idx=ProviderState.items.indexOf(item);
如果(idx!=-1){
ProviderState.项目.拼接(idx,1);
}
}
静态通知(newState){
ProviderState.state=新闻状态;
ProviderState.items.forEach(item=>item.setState(newState));
}
静态={foo:0,bar:0};
}
//注册(侦听)共享状态的状态提供程序
常量提供程序=({reducer,children})=>{
const[state,setState]=React.useState(ProviderState.state);
反作用(
() => {
const entry={reducer,setState};
ProviderState.注册表(条目);
return()=>{
ProviderState.注销(条目);
};
},
[]
);
返回(
{
const newState=reducer(ProviderState.state,action);
if(newState!==ProviderState.state){
ProviderState.notify(新闻状态);
}
}
}}
>
{儿童}
);
}
//几个消费者
const Consumer1=()=>{
const{state,dispatch}=React.useContext(MyContext);
//console.log('render1');
返回分派({type:'inc_foo'})}>foo{state.foo}bar{state.bar}!;
};
const Consumer2=()=>{
const{state,dispatch}=React.useContext(MyContext);
//console.log('render2');
返回分派({type:'inc_bar'})}>bar{state.bar}foo{state.foo}!;
};
const reducer=(状态、操作)=>{
log('减少操作:',操作);
开关(动作类型){
案例“inc_foo”:
返回{
……国家,
foo:state.foo+1,
};  
案例“inc_bar”:
返回{
……国家,
bar:state.bar+1,
};
违约:
返回状态;
}
}
//在这里,提供程序在同一级别上使用,但任何深度都可以
类应用程序扩展了React.Component{
render(){
console.log('render app');
返回(
我不会再让我的孩子们喜欢我了
);
}
}
ReactDOM.render(,document.getElementById('root'))

如果希望在应用程序的多个部分之间共享一个值,则需要以某种形式将该值向上移动到需要使用该值的部分的公共祖先组件。正如您在评论中提到的,您的问题是性能问题,并且尽量不重播所有内容。拥有两个提供者并不能真正起到帮助作用,因为仍然需要一些组件来确保两个提供者提供相同的值。因此,该组件最终需要成为两个提供者的共同祖先

相反,您可以使用shouldComponentUpdate(对于类组件)或React.memo(对于功能组件)来阻止重新排序进程沿着组件树向下运行。使用Context.Consumer的深层子代仍将重新命名,因此您可以跳过树的中间部分。下面是一个示例(注意在中间组件上使用React.memo):

const Context=React.createContext(未定义);
const useCountRenders=(名称)=>{
const count=React.useRef(0);
React.useffect(()=>{
count.current++;
console.log(名称、计数、当前值);
});
}
常量应用=()=>{
const[val,setVal]=React.useState(1);
useCountRenders(“应用程序”);
React.useffect(()=>{
设置超时(()=>{
console.log(“更新应用程序”);
setVal(val=>val+1)
}, 1000);
}, [])
返回(
);
}
常量中间组件=React.memo((道具)=>{
useCountRenders(“中间”);
返回(
);
})
const Consumer=(道具)=>{
useCountRenders(道具名称);
返回(
{val=>{
console.log('running consumer child',props.name);
返回消耗{val}
}}
)
}
常量未更新组件=(道具)=>{
useCountRenders(“无关”);
返回props.children | | null;
}
ReactDOM.render(,document.getElementById('root'))

我不想(几乎)为所有c语言提供上下文