React useReducer返回状态与日志值不一致,UID调度增量异常
问题原因
这个问题是开发环境下React StrictMode(严格模式)的行为和非纯函数reducer共同导致的:
- React 18+的严格模式在开发环境中,会对reducer这类要求纯函数的逻辑执行两次,目的是提前检测非纯函数导致的异常问题
- 你的reducer依赖了外部可变的全局变量
uid,不属于纯函数:每次调用都会修改外部的uid值,两次调用就会让uid累加两次 - 同时严格模式会自动静默第二次reducer调用产生的
console.log输出,所以你只能看到第一次调用的打印结果,但是实际采用的是第二次调用后的返回值,自然就出现了打印值和渲染值差1、每次累加2的情况
你用useRef存uid也会有同样问题,因为ref的值是可变的,reducer依赖ref的话依然不属于纯函数,严格模式下两次调用同样会修改两次ref的值。
这个问题只会在开发环境出现,生产环境下严格模式不会重复调用reducer,但不建议依赖这个行为,保持reducer是纯函数是React的官方最佳实践。
修复方案
将uid存入reducer管理的state中,保证reducer是纯函数,状态变更完全由传入的state和action决定即可:
import React, { useReducer } from "react" function reducer(state, action) { switch (action.type) { case "increment": const newUid = state.uid + 1 return { uid: newUid, text: `current UID is ${newUid}!` } default: return state } } function TestComponent() { const [state, dispatch] = useReducer(reducer, { uid: 0, text: "not clicked yet" }) return <button onClick={() => dispatch({ type: "increment" })}>{state.text}</button> } export default TestComponent
这个写法下reducer是纯函数,两次调用返回的结果完全一致,严格模式的重复调用不会产生任何异常。
内容的提问来源于stack exchange,提问作者Codehardt
相关产品推荐
相关产品推荐

