Redux Toolkit中不可变性是什么?如何实现?代码是否合规?
Redux Toolkit 中的不可变性及自定义不可变Reducer解析
一、Redux Toolkit 中的不可变性是什么
Redux 的核心规则之一是状态不可变:你永远不能直接修改 Redux 存储中的原始状态对象或数组,必须通过创建新的状态副本并替换原状态来完成更新。这是因为 Redux 依赖状态引用的变化来检测状态更新,进而触发相关组件的重渲染。
Redux Toolkit(RTK)默认集成了 Immer 库,它允许你编写看似“直接修改状态”的代码,背后会自动将这些可变操作转换为符合不可变性要求的新状态副本。但如果你想手动实现不可变逻辑,就需要完全遵循“不修改原状态,只返回新状态”的规则。
二、手动实现不可变Reducer的核心方法
手动编写不可变Reducer时,核心是为需要更新的层级创建新的副本:
- 数组操作:使用扩展运算符
[...]、filter、map等返回新数组的方法,避免直接修改原数组的元素或长度。 - 对象操作:使用扩展运算符
{...obj}或Object.assign创建新对象,避免直接修改原对象的属性。
三、你的代码分析与修正
你当前的代码是基于 Immer 的“可变写法”(直接修改 state 对象),虽然最终效果符合不可变性要求,但依赖于 Immer 的自动转换。如果要完全手动实现不可变逻辑,需要修改为返回新状态对象的写法,不直接修改入参 state:
修正后的代码
import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { Tab } from '../../logic/types' import { TabsState, updateTabPayload } from '../types' const initialState: TabsState = { tabs: [] } export const tabsSlice = createSlice({ name: 'tabs', initialState, reducers: { loadTabs: (state, action: PayloadAction<Tab[]>) => { // 返回新的状态对象,不修改原state return { ...state, tabs: [...state.tabs, ...action.payload] } }, createTab: (state, action: PayloadAction<Tab>) => { return { ...state, tabs: [...state.tabs, action.payload] } }, updateTab: (state, action: PayloadAction<updateTabPayload>) => { const { id, update } = action.payload // 使用map创建新数组,找到目标项时返回新对象 const updatedTabs = state.tabs.map(tab => tab.id === id ? { ...tab, ...update } : tab ) return { ...state, tabs: updatedTabs } }, deleteTab: (state, action: PayloadAction<number>) => { return { ...state, tabs: state.tabs.filter(tab => tab.id !== action.payload) } } } }) export const { loadTabs, createTab, updateTab, deleteTab } = tabsSlice.actions export default tabsSlice.reducer
关键修改点说明
- 所有reducer均返回新状态对象:不再直接修改
state.tabs,而是通过扩展运算符拷贝原状态的其他属性,仅替换需要更新的tabs数组。 - updateTab的修改:原代码直接修改数组的指定索引项(
state.tabs[index] = ...)属于可变操作,修正后使用map创建新数组,对匹配到的项返回新的对象副本,其余项保持原引用。 - 统一action参数命名:将原代码中的
tabs、tab、data、id统一改为action,符合Redux Toolkit的常规写法,避免变量名混淆。
内容的提问来源于stack exchange,提问作者zaiyhu
相关产品推荐
相关产品推荐

