React.useReducer内部更新状态的最优方法选择及原因详解
Reducer状态更新最优方案问题
我们先来看一个简单的reducer示例:
首先是useReducer的声明代码:
const [state, setState] = React.useReducer(myReducer, {})
简化版myReducer仅包含一个case分支,代码如下:
const myReducer = (state, action) => { switch (action.type) { case 'UPDATE_STATE': { // 此处编写状态更新逻辑 } } }
已知前提:payload = state,现有以下4种状态更新写法,请问哪一种是更新状态的最优方案,并说明具体原因:
4种实现方案
- 方法1
case 'UPDATE_STATE': { const updatedState = action.payload updatedState.object = true return updatedState }
- 方法2
case 'UPDATE_STATE': { const updatedState = action.payload updatedState.object= true return { ...state, updatedState } }
- 方法3
case 'UPDATE_STATE': { const updatedState = action.payload updatedState.object= true return { ...state, ...updatedState } }
- 方法4
case 'UPDATE_STATE': { return ({ ...state, object: true }) }
结论
最优方案是方法4,具体原因如下:
React中reducer的核心原则是必须为纯函数:不能修改入参的原状态/原参数,必须返回全新的状态对象,这样React才能正确检测状态变化触发重渲染。
各方案问题分析
- 方法1的问题
已知payload = state,也就是action.payload是原状态对象的引用,直接修改updatedState.object = true属于直接篡改原状态,违反了reducer纯函数要求,会导致React无法检测到状态变化,出现重渲染异常的bug。 - 方法2的问题
首先同样存在直接修改原状态的问题,其次返回的结构{ ...state, updatedState }相当于给新状态新增了一个名为updatedState的属性,完全不符合预期的状态结构,逻辑错误。 - 方法3的问题
还是存在直接修改原状态的核心问题,即使后续做了解构合并,前面的原对象修改已经违反了纯函数要求,会带来不可预期的bug,同时代码冗余,多了不必要的临时变量操作。 - 方法4的优势
完全符合reducer的设计规范:
- 没有修改任何入参,无副作用,是标准纯函数
- 通过展开运算符
...state保留原状态所有属性,显式覆盖object属性为true,逻辑清晰简洁 - 无多余的临时变量声明,执行效率最高
- 返回的是全新的状态对象,React可以正常检测到状态变更,不会出现重渲染异常
内容的提问来源于stack exchange,提问作者user10613856
相关产品推荐
相关产品推荐

