如何让不同createRoot渲染的函数组件共享React Context(无需Redux)
问题:如何在两个通过不同
createRoot渲染的函数组件间共享上下文? 当前问题:<Annotation>组件获取的状态与<Chat>组件不一致。
限制条件:无法使用Redux,应用体量很小因此未采用。
需要修改context.js实现状态共享,现有代码如下:
index.js
import { AppContext, AppContextProvider } from "./context"; const BookBot = (props) => { const botRoot = createRoot(document.getElementById((props?.toolbox))) const botAnnot = createRoot(document.getElementById((props?.annotbox))) botRoot.render( <AppContextProvider> <Chat /> </AppContextProvider> ); botAnnot.render( <AppContextProvider> <Annotation /> </AppContextProvider> ) }
context.js
const AppContext = React.createContext([{}, () => {}]); const AppContextProvider = (props) => { const [state, setState] = useState({ chats:[], query:undefined, sendDisabled:false, chatId:"" }); return ( <AppContext.Provider value={[state, setState]}> {props.children} </AppContext.Provider> ); }; export { AppContext, AppContextProvider };
解决方案
问题核心在于你给两个独立的createRoot分别套了一个AppContextProvider,每个Provider内部都创建了独立的useState状态实例,导致两个组件的状态完全隔离。要实现共享,需让两个Provider复用同一个状态,以下是两种可行方案:
方案1:让Provider接收外部传入的状态(推荐)
把AppContextProvider改为受控组件,不再内部创建状态,而是通过props接收外部的状态和更新方法:
修改context.js
const AppContext = React.createContext([{}, () => {}]); // 改为接收外部传入的state和setState const AppContextProvider = (props) => { const { state, setState, children } = props; return ( <AppContext.Provider value={[state, setState]}> {children} </AppContext.Provider> ); }; export { AppContext, AppContextProvider };
修改index.js
将状态提升到BookBot组件中,把同一个state和setState传递给两个Provider:
import { useState } from 'react'; import { AppContext, AppContextProvider } from "./context"; const BookBot = (props) => { // 在这里创建共享状态 const [state, setState] = useState({ chats:[], query:undefined, sendDisabled:false, chatId:"" }); const botRoot = createRoot(document.getElementById((props?.toolbox))) const botAnnot = createRoot(document.getElementById((props?.annotbox))) botRoot.render( <AppContextProvider state={state} setState={setState}> <Chat /> </AppContextProvider> ); botAnnot.render( <AppContextProvider state={state} setState={setState}> <Annotation /> </AppContextProvider> ) }
这样修改后,两个组件将共享同一个状态实例,状态变更时会同步更新。
方案2:使用全局状态单例(小型应用可选)
如果不想修改Provider结构,可在context.js中创建全局状态单例(不推荐大型应用使用):
修改context.js
const AppContext = React.createContext([{}, () => {}]); // 创建全局状态单例 let globalState; let globalSetState; const AppContextProvider = (props) => { const [state, setState] = useState({ chats:[], query:undefined, sendDisabled:false, chatId:"" }); // 仅在首次渲染时初始化全局状态 if (!globalState) { globalState = state; globalSetState = setState; } // 所有Provider复用全局状态 return ( <AppContext.Provider value={[globalState, globalSetState]}> {props.children} </AppContext.Provider> ); }; export { AppContext, AppContextProvider };
这种方式无需修改index.js,但要注意:只有第一个渲染的AppContextProvider会初始化全局状态,后续Provider都会复用该状态。
内容的提问来源于stack exchange,提问作者MN_
相关产品推荐
相关产品推荐

