React useContext中dispatch更新的状态未在所有组件同步如何解决
问题原因及解决方案
根因分析
- 你的teams状态初始化逻辑(
dispatch(setTeams))写在了仅首页路由/才会渲染的GetTeamsByFiles组件的空依赖useEffect中,该逻辑只有组件挂载时才会执行 - 你配置的两个路由是互斥关系:当访问
/:teamName路由时,GetTeamsByFiles组件不会被渲染,初始化逻辑从未执行,state中的teams始终是初始值 - 如果你是从首页用原生a标签跳转,会触发页面整体刷新,App组件重新挂载,之前更新的state会被重置为初始值,跳转后
GetTeamsByFiles不渲染,自然也不会重新执行初始化
解决方案
方案1(推荐):将初始化逻辑移到全局App组件
App组件在所有路由下都不会卸载,将初始化逻辑放在App的useEffect中即可保证所有路由都能拿到更新后的状态,修改后App组件代码如下:
import "bootstrap/dist/css/bootstrap.min.css"; import "./App.css"; import { GetTeamsByFiles } from "./components/GetTeamsByFiles"; import { RenderCheckbox } from "./components/RenderCheckbox"; import { BrowserRouter, Switch, Route } from "react-router-dom"; import { useReducer, useEffect } from "react"; import { reducer, setTeams } from "./state/reducer"; import { initialState } from "./state/state"; import { Context } from "./state/context"; function App() { const [state, dispatch] = useReducer(reducer, initialState); // 全局初始化teams数据 useEffect(() => { dispatch(setTeams([ { name: "FKP1-Komplett", members: ["Lars", "Tobias", "Falko", "Sami"] }, { name: "FKP1-Entwickler", members: ["Lars", "Tobias"] }, { name: "FKP2-Komplett", members: ["Tessa", "Volker", "Robert", "Viktor", "Ahmed", "Patrick"], }, { name: "FKP2-Entwickler", members: ["Tessa", "Volker", "Robert", "Viktor"], }, ])) }, [dispatch]) return ( <div className="App"> <Context.Provider value={{state,dispatch}}> <BrowserRouter> <Switch> <Route exact path="/" component={GetTeamsByFiles}></Route> <Route path="/:teamName" component={RenderCheckbox}></Route> </Switch> </BrowserRouter> </Context.Provider> </div> ); } export default App;
修改后可以删除GetTeamsByFiles组件中原来的初始化useEffect逻辑。
方案2:适配首页初始化的业务逻辑
如果你的业务逻辑要求必须在首页组件中执行初始化,需要同时满足两个条件:
- 所有页面跳转使用react-router-dom提供的
Link/navigate接口,禁止使用原生a标签,避免页面刷新导致状态重置 - 必须先访问首页完成初始化,再跳转到子路由,直接访问子路由依然拿不到更新后的状态
补充排查点
检查你的initialState定义中是否存在teams字段,字段名和类型要和reducer中更新的字段完全匹配,避免拼写错误导致更新失效。
内容的提问来源于stack exchange,提问作者MNozdratchev
相关产品推荐
相关产品推荐

