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

Redux Toolkit createSlice无法更新数组状态问题

问题现象

在Redux中存储对象数组,使用@reduxjs/toolkit的createSlice()编写状态更新逻辑时,仅state.push()新增元素的操作可以正常生效,其余修改、删除、整体替换数组的操作均无法触发状态更新。通过Redux DevTools观测,调用updateDashboard等方法后状态无任何变化,异步拉取的初始状态数组共包含10个元素。

问题复现代码如下:

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { BACKEND_API } from "../../utilities/environment";
import fetchViaApi from "../../utilities/fetchViaApi";

export const getInitialDashboards = createAsyncThunk(
    'dashboard/getDashboards',
    async () => {
        const response = await fetchViaApi('/dashboards', {
            baseUrl: BACKEND_API,
            method: "GET"
        });

        const data = await response.json();
        return data;
    }
)

const initialState = [];

const dashboardsSlice = createSlice({
    name: 'dashboards',
    initialState,
    reducers: {
        setDashboards: (state,action) => {
            state = action.payload;
        },
        updateDashboard: (state,action) => {
            // state.push(action.payload);
            state = [...state.slice(0, 5)];
        },
        deleteDashboard: (state, action) => {
        },
    },
    extraReducers: builder => {
        builder.addCase(getInitialDashboards.fulfilled, (state, action) => {
            action.payload.forEach(element => {
                state.push(element);
            });
        })
    }
});

export const { setDashboards, updateDashboard, editDashboard, deleteDashboard } = dashboardsSlice.actions;

export default dashboardsSlice.reducer;

问题复现截图:
问题复现截图

根本原因

createSlice 内部基于Immer实现不可变更新,reducer中的state是Immer包装的draft代理对象,状态更新只有两种合法写法:

  • 直接修改draft对象本身(比如调用push/splice等会改变原数组的方法、直接给数组下标位/对象属性赋值)
  • 显式return全新的状态值,Immer会直接将该值作为新的state

代码中写的state = xxx只是给函数内的局部形参变量重新赋值,既没有修改原始draft对象,也没有返回新值,Immer完全感知不到状态变更,自然不会触发更新。这也是为什么state.push()可以生效——push是直接操作draft数组本身的变更,能被Immer捕获。

另外代码中导出action时多解构了未在reducers中定义的editDashboard,这个导出值会是undefined,调用时也会报错。

修复代码

按照Immer的规则调整reducer写法即可,参考实现如下:

const dashboardsSlice = createSlice({
    name: 'dashboards',
    initialState,
    reducers: {
        setDashboards: (state,action) => {
            // 整体替换状态直接返回新值即可
            return action.payload;
        },
        updateDashboard: (state,action) => {
            // action.payload 约定为 { id: 待更新条目的ID, 其余为要更新的字段 }
            const updateData = action.payload;
            const targetIndex = state.findIndex(item => item.id === updateData.id);
            if (targetIndex > -1) {
                // 直接修改draft对应位置的对象,Immer会自动生成不可变更新
                state[targetIndex] = { ...state[targetIndex], ...updateData };
            }
        },
        deleteDashboard: (state, action) => {
            // action.payload 约定为待删除条目的ID
            const deleteId = action.payload;
            const targetIndex = state.findIndex(item => item.id === deleteId);
            if (targetIndex > -1) {
                // 通过splice直接修改原draft数组完成删除
                state.splice(targetIndex, 1);
            }
        },
    },
    extraReducers: builder => {
        builder.addCase(getInitialDashboards.fulfilled, (state, action) => {
            // 异步拉取初始值直接返回结果即可,不需要循环push
            return action.payload;
        })
    }
});

// 移除未定义的editDashboard导出
export const { setDashboards, updateDashboard, deleteDashboard } = dashboardsSlice.actions;

内容的提问来源于stack exchange,提问作者A. Hasemeyer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:30:42