为什么Redux reducer未返回新数组时,绑定的React组件仍会触发重渲染?
问题原因解析
你遇到的现象是两个隐含逻辑共同作用的结果,和Redux的不可变原则、useSelector的默认比对逻辑有关:
- 首先你在reducer中返回了新的外层state对象:你通过
Object.assign({}, state, { appInfos })创建了一个和原state结构一致的新对象,虽然appInfos数组还是原引用,但整个appInfosreducer返回的state已经是新的引用,对应store中的state.appInfos值的引用发生了变化。 - 其次你的
mapStateToProps函数每次执行都会返回一个全新的对象{app: state.appInfos},而useSelector默认采用**严格相等(===)**比对前后两次返回值,两次返回的是不同引用的对象,所以useSelector会判定值发生了变化,触发组件重新渲染。
另外你直接修改原state中appInfos[0].name的操作是违反Redux不可变原则的错误写法,这次能看到渲染结果只是巧合:因为你已经提前修改了原数组内对象的属性值,组件重新渲染时读取到的就是修改后的值。但这种写法会带来很多隐性bug,比如其他依赖appInfos数组引用、或者依赖数组内对象引用的组件,会因为引用没有变化,出现该更新却不更新的问题。
正确写法参考
严格遵循不可变原则修改state,每次修改都要创建新的数组和变更的元素对象:
case 'SET_APP_NAME': return { ...state, appInfos: [ // 只修改第一个元素,创建新的对象 {...state.appInfos[0], name: action.name}, // 剩余元素复用原引用 ...state.appInfos.slice(1) ] }
如果要避免mapStateToProps每次返回新对象导致的不必要渲染,可以给useSelector传入第二个参数shallowEqual开启浅比较:
import { shallowEqual, useSelector } from 'react-redux' const { app } = useSelector(mapStateToProps, shallowEqual)
内容的提问来源于stack exchange,提问作者labixiaoying
相关产品推荐
相关产品推荐

