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

Redux Toolkit如何更新深度嵌套数组对象中的remark_id?

Redux嵌套状态更新问题解决

问题背景

我是Redux新手,若有疏漏还请见谅。我的初始状态是一个深度嵌套的对象数组:

const initialState = {
    schedules: [
        {
            "id": 1,
            "role_id": 1,
            "rules": [
                {
                    "id": 1,
                    "module_id": 16,
                    "remark_id": 2,
                },
                ...
            ]
        },
        ...
    ]
}

我需要更新某个schedule对象下rules数组中的remark_id字段,尝试了以下代码但未生效:

updateRemark: (state, action) => {
    const { remark_id, rule_id, schedule_id } = action.payload
        const schedule = state.schedules.find(schedule => schedule.id == schedule_id)
        if (schedule) {
            const rule = schedule.rules.find(rule => rule.id == rule_id)
            if (rule) {
                rule.remark_id = remark_id
            }
        }
    },

我参考了Redux Toolkit官方关于嵌套数据更新的文档,核心内容是:Redux Toolkit集成的Immer库允许你以“可变”的写法编写状态更新逻辑,但底层会自动生成不可变的状态副本。对于嵌套数组这类复杂结构,需要确保Immer能正确追踪到状态的变更。

解决方案

问题出在直接修改find返回的对象时,Immer可能无法正确识别数组的变更(因为数组本身的引用没有改变)。推荐两种可行写法:

写法一:传统不可变更新(手动生成新数组/对象)

updateRemark: (state, action) => {
    const { remark_id, rule_id, schedule_id } = action.payload;
    // 遍历schedules数组,定位目标schedule并更新其rules
    state.schedules = state.schedules.map(schedule => {
        if (schedule.id !== schedule_id) {
            return schedule; // 无需修改的项直接返回原对象
        }
        // 定位目标schedule后,遍历其rules数组更新对应rule
        return {
            ...schedule,
            rules: schedule.rules.map(rule => {
                if (rule.id !== rule_id) {
                    return rule;
                }
                // 更新目标rule的remark_id
                return {
                    ...rule,
                    remark_id: remark_id
                };
            })
        };
    });
}

写法二:Immer可变写法(更简洁)

updateRemark: (state, action) => {
    const { remark_id, rule_id, schedule_id } = action.payload;
    // 找到目标schedule的索引
    const scheduleIndex = state.schedules.findIndex(s => s.id === schedule_id);
    if (scheduleIndex !== -1) {
        // 找到目标rule的索引
        const ruleIndex = state.schedules[scheduleIndex].rules.findIndex(r => r.id === rule_id);
        if (ruleIndex !== -1) {
            // 直接修改对应索引的rule属性,Immer自动处理不可变更新
            state.schedules[scheduleIndex].rules[ruleIndex].remark_id = remark_id;
        }
    }
}

原因说明

第一种写法通过解构和map生成新的数组与对象,符合Redux不可变更新的核心要求;第二种写法利用Immer的特性,直接修改数组索引对应的元素,Immer会在底层追踪修改并生成新的状态副本,写法更直观。

原代码中,find返回的是对象代理,但直接修改对象属性时,未触发数组的引用变化,Immer无法正确标记状态变更,导致组件无法感知到状态更新。而通过修改数组索引或生成新数组的方式,能确保Immer正确追踪状态变化,从而触发组件重新渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:09:17