如何在NgRx Reducer中向State嵌套对象的数组添加元素
NgRx Reducer中向嵌套Deck对象添加Card的解决方案
问题核心
NgRx Reducer必须遵循状态不可变原则,不能直接修改原State对象。直接调用currentDeck.addCard(card)会修改State中的原始对象,触发"can't define array index property past the end of an array with non-writable length"错误,必须通过创建副本的方式实现状态更新。
解决方案(无需安装Immer)
提供两种符合不可变原则的实现方式:
方式一:基于Deck类方法创建副本
先复制当前currentDeck实例,在副本上调用addCard方法后替换原对象:
on(addCardToCurrentDeckActions.addCardCurrentDeckSuccess, (state, { card }) => { // 处理currentDeck未初始化的边界情况 if (!state.currentDeck) return state; // 创建Deck实例的完整副本 const updatedDeck = new Deck(); updatedDeck.deckId = state.currentDeck.deckId; updatedDeck.name = state.currentDeck.name; // 复制原cards数组,避免直接引用原数组 updatedDeck.cards = [...state.currentDeck.cards]; // 在副本上执行添加操作 updatedDeck.addCard(card); return { ...state, currentDeck: updatedDeck }; })
方式二:手动构造新Deck对象(更简洁)
利用对象扩展语法直接创建新Deck对象,同时更新cards数组,无需依赖Deck类的方法:
on(addCardToCurrentDeckActions.addCardCurrentDeckSuccess, (state, { card }) => { if (!state.currentDeck) return state; return { ...state, currentDeck: { ...state.currentDeck, // 复制原cards数组并追加新Card cards: [...state.currentDeck.cards, card] } }; })
关键说明
- 两种方式均未修改原State中的任何对象/数组,严格遵守NgRx不可变规则
- 必须先判断
currentDeck是否存在,避免undefined引发的运行时错误 - 方式二更简洁高效,无需手动复制Deck的其他属性,直接通过扩展语法生成新对象
内容的提问来源于stack exchange,提问作者Nayrb
相关产品推荐
相关产品推荐

