You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Redux选择数组时避免多余重渲染的正确方法是什么?

问题根因

你遇到的问题本质是默认Reselect选择器使用引用相等判断依赖是否变化,只要state.items的引用发生变更(比如修改其中某个元素的非id属性时的不可变更新),就会触发selectIds重新计算,返回新的数组引用,进而触发组件重渲染。

解决方案

方案1:自定义带id感知的Reselect选择器(最推荐)

Reselect支持通过createSelectorCreator自定义选择器的依赖比较规则,你可以把依赖items的比较逻辑从默认的引用相等,改为只判断items的id序列是否变化,只有id真的变化时才重新计算id数组:

  1. 编写id比较函数
// 比较两个items数组的id序列是否完全一致
const isItemsIdEqual = (prevItems: Item[], nextItems: Item[]) => {
  if (prevItems === nextItems) return true
  if (prevItems.length !== nextItems.length) return false
  for (let i = 0; i < prevItems.length; i++) {
    if (prevItems[i].id !== nextItems[i].id) return false
  }
  return true
}
  1. 创建自定义选择器构造器
import { createSelectorCreator, defaultMemoize } from 'reselect'

// 构造专门处理items数组的选择器,用id相等判断依赖是否变化
const createIdAwareSelector = createSelectorCreator(
  defaultMemoize,
  isItemsIdEqual
)
  1. 重写selectIds选择器
const selectItems = (state: MyStateType) => state.items

const selectIds = createIdAwareSelector(
  selectItems,
  (items) => items.map(item => item.id)
)

改造后,只有当items发生增删、排序、id修改时,才会触发selectIds重新计算,返回新的id数组;如果只是修改某个元素的其他属性,selectIds会直接返回之前缓存的数组引用,useSelector默认的引用相等校验就会认为值没有变化,不会触发组件重渲染。且id比较逻辑只会在Redux状态变更时执行一次,全局共享缓存,比在useSelector中传自定义比较函数的性能高很多。

改造后无需在useSelector中额外传入自定义比较函数,默认的引用相等校验就够用。

方案2:Reducer层单独维护id列表(极致性能场景)

如果你的items数组量级特别大(几千条以上),且dispatch调用非常频繁,可以直接在Reducer中额外维护一个allIds字段,专门存储所有item的id:

// state结构
state = {
  items: [{id: 1, keys...}, {id: 2, keys...}, ...],
  allIds: [1,2,3,...]
}

只有当执行增删item、修改id、调整顺序的操作时,才更新allIds的引用,修改item其他属性时不需要改动allIds。此时选择器可以直接取state.allIds,完全不需要计算,性能最高。缺点是需要维护两份关联数据,更新时要保证两者同步。

内容的提问来源于stack exchange,提问作者newimprovement

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 04:45:04