使用useMemo阻止组件重渲染失效,相同Redux状态仍触发更新怎么办?
问题分析
你的useMemo使用方式确实是错误的,出现这个问题的核心原因有3个:
- JavaScript中对象为引用类型,每30秒接口返回的就算是内容完全相同的对象,只要你是直接把新返回的对象赋值给Redux状态,就会生成全新的内存引用,
useSelector默认做浅比较检测到引用变化,就会返回新的对象给组件。 - 你写的
useMemo没有实际作用:你把details本身作为依赖项,useMemo默认对依赖做浅比较,每次details引用变化就会重新执行回调返回新的对象,你没有在逻辑中做内容是否相等的判断,等于完全没有实现缓存效果。 - 你的代码存在变量名笔误:定义的缓存变量名为
memorizedDetails,但useEffect中依赖的是memorizedOrderDetails,如果实际项目中也是这种写法也会触发逻辑异常。
解决方案
方案1:给useSelector传入深度比较函数(最便捷)
Redux的useSelector支持传入第二个参数作为相等性判断函数,你可以直接用它实现内容级别的比较,无需额外使用useMemo:
import { isEqual } from 'lodash'; // 也可以自己实现适配业务的深度比较函数,避免引入lodash const details = useSelector( (state: RootState) => state.orders.details, isEqual );
只要前后两次的details内容完全一致,useSelector就会返回旧的引用,不会触发组件重渲染,依赖details的useEffect也不会执行。
方案2:在Redux reducer层做引用复用(全局生效)
在更新details的reducer逻辑中先做内容比较,如果新返回的接口数据和旧状态内容完全一致,直接返回旧的状态,从根源上避免不必要的状态更新:
import { isEqual } from 'lodash'; const initialState = { details: {} } const ordersReducer = (state = initialState, action) => { switch(action.type) { case 'ORDERS/UPDATE_DETAILS': // 内容相同直接返回旧状态,引用保持不变 if (isEqual(state.details, action.payload)) return state; return { ...state, details: action.payload }; default: return state; } }
这种方式的好处是全局所有用到state.orders.details的组件都能自动享受到性能优化,无需在每个组件中单独处理。
内容的提问来源于stack exchange,提问作者CraZyDroiD
相关产品推荐
相关产品推荐

