为何无法在全局Context中存储useState的getter/setter?
为什么通过Context传递useState状态后,setNum调用未生效?
问题场景
操作步骤:
- Page1通过
useState创建初始值为0的状态num,并将其getter/setter存入App中的Context; - Page2通过Context获取
num的setter并将num设为1; - Page3通过Context获取
num值并展示。
预期Page3显示num=1,但实际显示num=0,setNum调用未按预期生效。
原代码
App.js
import { useState } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; import { SharedContext } from './context'; function App() { const [context, setContext] = useState(null); return ( <BrowserRouter> <SharedContext.Provider value={{ context, setContext }}> <Routes> <Route path="/" element={<Page1 />} /> <Route path="/page2" element={<Page2 />} /> <Route path="/page3" element={<Page3 />} /> </Routes> </SharedContext.Provider> </BrowserRouter> ); }
Page1.js
import { useNavigate, useContext, useState, useEffect } from 'react'; import { SharedContext } from './context'; export default function Page1() { const navigate = useNavigate(); const { setContext } = useContext(SharedContext); const numState = useState(0); useEffect(() => { setContext(numState); }, []); const onClick = () => { navigate('/page2'); }; return <button onClick={onClick}>Next</button>; }
Page2.js
import { useNavigate, useContext } from 'react'; import { SharedContext } from './context'; export default function Page2() { const navigate = useNavigate(); const { context } = useContext(SharedContext); const [num, setNum] = context; const onClick = () => { setNum(1); navigate('/page3'); }; return <button onClick={onClick}>Next</button>; }
Page3.js
import { useContext } from 'react'; import { SharedContext } from './context'; export default function Page3() { const { context } = useContext(SharedContext); const [num, setNum] = context; return <div>num = {num}</div>; }
问题原因
核心问题是Page1组件卸载后,它内部创建的useState状态会被React销毁:
- 当从Page1跳转到Page2时,Page1组件被卸载,它创建的
numState对应的状态容器和setNum函数都失去了作用——你在Page2调用的setNum是关联到已销毁组件的函数,根本无法更新任何活跃的状态。 - App组件中的
context状态只在Page1挂载时被设置了一次,后续没有任何更新,Page3拿到的还是最初存储的、关联到已销毁组件的状态数组,自然显示初始值0。
修复方案
正确的做法是把状态提升到Context的Provider所在组件(App组件),让状态的生命周期和App绑定,不会因为页面跳转被销毁。
修改后的代码
App.js
import { useState } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; import { SharedContext } from './context'; import Page1 from './Page1'; import Page2 from './Page2'; import Page3 from './Page3'; function App() { // 直接在App中创建共享状态 const [num, setNum] = useState(0); return ( <BrowserRouter> <SharedContext.Provider value={{ num, setNum }}> <Routes> <Route path="/" element={<Page1 />} /> <Route path="/page2" element={<Page2 />} /> <Route path="/page3" element={<Page3 />} /> </Routes> </SharedContext.Provider> </BrowserRouter> ); } export default App;
Page1.js
import { useNavigate } from 'react'; export default function Page1() { const navigate = useNavigate(); const onClick = () => { navigate('/page2'); }; return <button onClick={onClick}>Next</button>; }
Page2.js
import { useNavigate, useContext } from 'react'; import { SharedContext } from './context'; export default function Page2() { const navigate = useNavigate(); const { setNum } = useContext(SharedContext); const onClick = () => { setNum(1); navigate('/page3'); }; return <button onClick={onClick}>Next</button>; }
Page3.js
import { useContext } from 'react'; import { SharedContext } from './context'; export default function Page3() { const { num } = useContext(SharedContext); return <div>num = {num}</div>; }
这样修改后,状态由App组件持有,所有页面通过Context访问的都是同一个活跃的状态,调用setNum后状态会正确更新,Page3就能显示num=1了。
内容的提问来源于stack exchange,提问作者Andrew Ewert
相关产品推荐
相关产品推荐

