React中useState更新后Context未同步至其他组件的排查求助
React Context API 跨路由组件无法获取更新后值的问题
问题现象
- About页面可正常获取
testItem初始值 - Home页面点击TEST按钮时,
setTestItem能正常更新值,再次点击按钮可打印更新后的结果 - 切换至About页面点击TEST2按钮,始终打印初始值,无法获取Home页面更新后的最新值
排查过的方向
- 确认了Provider的包裹范围
- 考虑过set函数的异步特性,但未解决问题
相关代码
index.js
import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; import TestContextProvider from "./context/test-context"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <TestContextProvider> <App /> </TestContextProvider> </React.StrictMode> ); reportWebVitals();
App.js(路由配置)
import logo from "./logo.svg"; import "./App.css"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import Home from "./components/Home"; import About from "./components/About"; function App() { return ( <Router> <Routes> <Route element={<Home />} path="/"></Route> <Route element={<About />} path="/about"></Route> </Routes> </Router> ); } export default App;
test-context.jsx
import React, { useState } from "react"; export const TestContext = React.createContext({ testItem: 1, setTestItem: () => {}, }); export const TestContextProvider = (props) => { const [testItem, setTestItem] = useState(1); return ( <TestContext.Provider value={{ testItem: testItem, setTestItem: setTestItem }} > {props.children} </TestContext.Provider> ); }; export default TestContextProvider;
Home组件
import React, { useContext } from "react"; import { TestContext } from "../context/test-context"; function Home() { const ctx = useContext(TestContext); const handleOnClick = () => { console.log(ctx.testItem); ctx.setTestItem((i) => i + 1); }; return ( <div> Home <button onClick={handleOnClick}>TEST</button> </div> ); } export default Home;
About组件
import React, { useContext } from "react"; import { TestContext } from "../context/test-context"; const About = () => { const ctx2 = useContext(TestContext); const handleOnClick2 = () => { console.log(ctx2.testItem); }; return ( <div> About <button onClick={handleOnClick2}>TEST2</button> </div> ); }; export default About;
解决方案
你的代码逻辑本身没有错误,问题根源是路由切换时使用了浏览器刷新/手动输入地址的方式,导致React应用重新初始化,Context状态被重置。
解决步骤1:使用React Router导航组件切换路由
修改App.js,添加Link组件实现路由跳转,避免页面刷新:
import logo from "./logo.svg"; import "./App.css"; import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom"; import Home from "./components/Home"; import About from "./components/About"; function App() { return ( <Router> <nav style={{ padding: '1rem' }}> <Link to="/">Home</Link> | <Link to="/about">About</Link> </nav> <Routes> <Route element={<Home />} path="/"></Route> <Route element={<About />} path="/about"></Route> </Routes> </Router> ); } export default App;
通过点击导航链接切换页面,Context状态会被正确保留,About页面即可获取Home更新后的testItem值。
解决步骤2:持久化状态(可选,应对页面刷新场景)
如果需要页面刷新后仍保留状态,可将Context数据存入localStorage:
修改test-context.jsx:
import React, { useState, useEffect } from "react"; export const TestContext = React.createContext({ testItem: 1, setTestItem: () => {}, }); export const TestContextProvider = (props) => { // 从localStorage读取初始值,无则用1 const [testItem, setTestItem] = useState(() => { return Number(localStorage.getItem('testItem')) || 1; }); // 值变化时同步到localStorage useEffect(() => { localStorage.setItem('testItem', testItem); }, [testItem]); return ( <TestContext.Provider value={{ testItem, setTestItem }} > {props.children} </TestContext.Provider> ); }; export default TestContextProvider;
这样即使页面刷新,状态也会从localStorage中恢复,确保跨页面数据一致性。
内容的提问来源于stack exchange,提问作者Denny Chen
相关产品推荐
相关产品推荐

