为什么React Context中使用useReducer无法更新状态?
问题修复方案
核心问题原因
useMemo依赖项缺失:你包裹authContext的useMemo依赖数组为空,导致authContext仅在App组件首次渲染时创建一次,后续无论状态怎么更新,authContext内的方法永远引用首次渲染时的初始loginState(email固定为null),不会同步最新状态。- 变量声明顺序错误:你先创建
authContext时用到了dispatch和loginState,但这两个变量是在后续才通过useReducer声明的,初始化阶段会拿到未定义值,逻辑顺序有误。 - React状态更新是异步机制:
dispatch触发reducer更新状态是批量异步处理的,调用dispatch后立刻打印loginState.email,拿到的必然是更新前的旧值,属于React正常运行机制。 - 组件命名不规范:
screenA首字母小写,React会将其识别为原生HTML标签而非自定义组件,可能引发渲染异常。
修复后代码
App.js
import React from 'react'; import AuthContext from './context'; import ScreenA from './screenA'; // 首字母大写符合React组件规范 export default function App() { const initialLoginState = { email: null, }; const loginReducer = (prevState, action) => { switch (action.type) { case 'Email': return { ...prevState, email: action.Email, }; default: return prevState; // 新增default分支兜底避免异常 } }; // 调整顺序:先声明useReducer,再创建authContext const [loginState, dispatch] = React.useReducer( loginReducer, initialLoginState, ); const authContext = React.useMemo( () => ({ email: emailUser => { dispatch({type: 'Email', Email: emailUser}); // 此处无法打印更新后的值,可通过useEffect监听loginState查看最新状态 }, signIn: async () => { try { await fetch('FakeApi', { // 新增await处理异步请求 method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ email: loginState.email, date: '2021-9-20', }), }); } catch (e) { console.log(e); } }, }), [loginState], // 加入loginState作为依赖,状态更新时同步刷新context ); return ( <AuthContext.Provider value={authContext}> <ScreenA /> </AuthContext.Provider> ); }
screenA.js(文件名同步改为ScreenA.js)
import React from 'react'; import { View, Button } from 'react-native'; // 补全原生组件导入 import {AuthContext} from './context'; function ScreenA() { const {email,signIn} = React.useContext(AuthContext); return ( <View style={{marginTop: 150}}> <Button title="sent email" onPress={() => { email('example@gmail.com'); }} /> <Button title="signIn" onPress={() => { signIn(); }} /> </View> ); } export default ScreenA;
额外调试建议
如果需要查看email更新后的最新值,可以在App组件中添加监听逻辑:
React.useEffect(() => { console.log('最新email值:', loginState.email); }, [loginState.email]);
内容的提问来源于stack exchange,提问作者Ali Mahmoudi
相关产品推荐
相关产品推荐

