创见博客
Redux修改状态,什么时候组件会重渲染?
七崽爱吃小饼干2026/01/13阅读 0专栏 React

RTK 状态修改后组件重渲染规则

一、 核心前提:RTK 不可变更新铁律

RTK 底层基于 Redux,状态变更的唯一有效方式是返回新的引用对象,这是组件能感知到状态变化的基础。

  1. Redux 浅比较机制:Redux 只对比 state 的引用地址,不对比对象内部属性。直接修改原 state(如 state.name = '新值'),引用地址不变 → Redux 判定状态未变 → 组件不渲染。
  2. RTK 的 Immer 自动优化:createSlice/createReducer 内置 Immer 库,允许在 reducer 中「看似直接修改 state」(如 state.user.name = '张三'),Immer 会自动转换为不可变更新,生成新的 state 引用。

二、 组件重渲染的核心判定规则

当 RTK 中任意 state 被修改(生成新引用)后,所有使用 useSelector 的组件都会触发一次对比校验(发布订阅模式),最终是否渲染完全取决于对比结果。

1. 全局触发 → 局部判定的完整流程

步骤具体操作
1 全局状态标记dispatch 触发 action → reducer 返回新 state 引用 → Redux 仓库标记「状态已变更」
2 全量执行回调所有使用 useSelector 的组件,重新执行自身的 useSelector 回调函数,获取最新返回值
3 新旧值对比拿最新返回值与上一次渲染的旧返回值做对比
4 渲染决策对比结果不同 → 组件重渲染;对比结果相同 → 组件不渲染

2. useSelector 对比规则(核心中的核心)

对比规则完全由 useSelector 返回值的类型决定,无任何例外:

返回值类型对比方式渲染判定示例
基础类型(string/number/boolean/null/undefined)直接对比值是否相等name 从 李四→张三 → 值变 → 渲染;name 从 张三→张三 → 值不变 → 不渲染
引用类型(对象/数组/函数)只对比内存引用地址是否相等新生成的 user 对象 → 地址变 → 渲染;返回临时新对象 {name, age} → 每次地址不同 → 无意义渲染

三、 高频误区与解决方案

1. 误区:返回临时引用类型导致无意义渲染

jsx
// ❌ 错误写法:每次执行都会返回新对象,地址永远不同
const userInfo = useSelector(state => ({
  name: state.user.name,
  age: state.user.age
}))

2. 解决方案(按优先级排序)

方案写法示例优势
拆分 useSelector(最优)const name = useSelector(state => state.user.name)
const age = useSelector(state => state.user.age)
无性能损耗,逻辑清晰,仅值变时渲染
记忆化选择器 createSelector(复杂场景推荐)const selectUser = state => state.user
const selectUserInfo = createSelector([selectUser], user => ({name: user.name, age: user.age}))
依赖状态不变时,返回缓存的旧引用,避免重复计算
浅比较函数 shallowEqual(兜底方案)import { shallowEqual } from 'react-redux'
const userInfo = useSelector(state => ({name, age}), shallowEqual)
对比对象第一层属性值,而非地址

四、 关键补充说明

  1. 深层属性修改的影响:修改深层属性(如 state.user.info.address)时,Immer 会生成新的 address→新的 info→新的 user,最终 user 引用地址改变,订阅 user 的组件会渲染。
  2. 全量对比 ≠ 全量渲染:所有组件的 useSelector 都会执行对比,但对比是极轻量的 JS 逻辑判断,无 DOM 操作;只有对比结果不同的组件才会触发重渲染,性能开销可忽略。
  3. 其他渲染触发因素:组件自身 useState 状态变化、父组件重渲染(未用 React.memo),也会导致组件渲染,与 RTK 状态无关。

五、 终极铁律(3 条即可覆盖所有场景)

  1. RTK 修改 state 后,所有用了 useSelector 的组件都会触发一次对比校验。
  2. 组件是否渲染,唯一依据是 useSelector 新旧返回值是否不同:基础类型比值,引用类型比地址。
  3. RTK 保证状态有效变更的核心是 Immer 自动实现不可变更新,生成新的 state 引用。
评论
0/100