如果 useSelector 返回的 state 数据很大,可能会导致 不必要的组件重新渲染,影响性能。优化方式主要有以下几种:
1. 精确选择数据,避免返回整个对象
错误做法(返回整个 state 对象):
问题:任何 state.bigData 内部的字段变化都会触发组件重新渲染,即使组件只用到其中一部分数据。
正确做法(只选择需要的字段):
优势:组件只会在 someValue 变化时重新渲染,而不会因 bigData 的其他字段变化而重新渲染。
2. 使用 reselect 进行 Memoization
如果计算 state 需要进行复杂的计算(如 filter、map 等),可以使用 reselect 缓存计算结果。
安装 reselect:
创建 selector:
组件中使用 selector:
优势:createSelector 只有在 state.bigData 变化时才会 重新计算,否则返回缓存结果。
避免不必要的计算,提升性能。
3. useSelector 第二个参数 equalityFn 自定义比较
默认情况下,useSelector 使用 浅比较(===) 来判断状态是否变化。如果 state 是 深层对象,可以使用 自定义比较函数 进行优化。
默认 useSelector(浅比较,可能会导致不必要的渲染):
使用 shallowEqual 进行浅层对比:
优势:shallowEqual 仅在 bigData 的 顶层字段 发生变化时才触发组件重新渲染。
自定义 equalityFn(仅在 id 变化时更新):
优势:避免 bigData 其他字段变化时,导致不必要的重新渲染。
4. 拆分 state,减少 store 更新影响范围
如果 bigData 很大,可以考虑拆分 store 结构,让 Redux 多个 slice 管理不同部分的数据。
优化前(单个 slice 存放大量数据):
优化后(拆分成多个 slice):
组件按需获取 state:
优势:避免 bigData 变化时,所有依赖 bigData 的组件都重新渲染。
5. 组件拆分,减少渲染范围
如果 useSelector 获取的数据很大,考虑 拆分组件,让子组件只订阅需要的数据。
错误示例(整个组件订阅大数据):
优化示例(拆分成子组件,每个子组件独立订阅状态):
优势:只有受影响的 ListItem 组件会重新渲染,而不是整个 ParentComponent。
6. 结合 useMemo 进行优化
如果 useSelector 返回的数据需要复杂计算,可以用 useMemo 缓存结果,避免重复计算。
错误示例(计算逻辑直接在 useSelector 内部):
优化示例(用 useMemo 缓存计算结果):
优势:useMemo 只有在 data 变化时才会重新计算,提高性能。
总结
优化方法 | 思路 | 适用场景 |
1. 精确选择数据 | useSelector 只返回 需要的字段,而不是整个 state | 适用于 state 体积大、变化频繁的情况 |
2. 使用 reselect | createSelector 缓存计算结果,避免重复计算 | 适用于 依赖计算、列表过滤 场景 |
3. 自定义 equalityFn | 只在 关键数据变化 时触发渲染 | 适用于 深层数据结构 |
4. 拆分 state | 将 state 拆成多个 slice,减少 store 影响范围 | 适用于 大规模应用 |
5. 组件拆分 | 让子组件独立订阅 state,避免父组件无意义渲染 | 适用于 列表渲染、大数据量场景 |
6. useMemo 缓存计算 | 避免 useSelector 内部重复计算 | 适用于 复杂计算 |
最终优化思路:
- 尽量让 useSelector 只选择最小数据。
- 使用 reselect 避免不必要的计算。
- 尽量拆分组件,减少不必要的渲染。
这样可以让 react-redux 更高效地更新 UI,提升应用性能!