我无法找出将新对象添加到状态块中包含的数组的正确语法。该数组是另一个对象的一部分,也是我状态的一部分。
在我的情况下,我有 Deck 对象,其中包含对象数组 Card[]。您可以在我的状态对象 currentDeck 中看到这一点。
我发现任何在reducer之外操作currentDeck的尝试都会导致错误“无法定义超过不可写长度的数组末尾的数组索引属性”。这让我意识到我需要做经过一番研究后,这在减速器中是正确的。
我有一个 NgRx 效果,它会发送一个成功操作,addCardCurrentDeckSuccess,将一张新卡添加到牌组中。这不仅需要更改 Cards 数组,还需要更改我假设的牌组。我发送的操作需要传入一张卡片,需要将其添加到 currentDeck 对象 Card[] 中。
我在 Deck 对象中有一个 addCard 方法,我认为解决方案中需要该方法。
我的代码和数据结构如下。我已经删除了大部分不相关的变量和其他减速器操作。
目前我正在寻找一种不需要安装“immer”模块的解决方案。我已经阅读了一些标准化数据集的文章,但我也不确定如何在这里做到这一点。
如有任何帮助,我们将不胜感激。
我的状态和Reducer
export interface MyState {
decks: [],
currentDeck : Deck;
}
export const initialState: MyState = {
currentDeck: undefined,
}
const reducer = createReducer(
initialState,
on(saveCurrentDeckActions.saveCurrentDeckSuccess, (state, { currentDeck }) => ({
...state,
currentDeck
})),
on(addDeckActions.addDeckSuccess, (state, { deck }) => ({
...state,
decks: [...state.decks, deck]
})),
on(addCardToCurrentDeckActions.addCardCurrentDeckSuccess, (state, { card }) => ({
/* Can't seem to nail down the syntax here
currentDeck.AddCard(card) */
}))
);
export const MyFeature = createFeature({
name: 'MyFeatureSelectors',
reducer
})
// Deck
import {Card} from "./card.model"
export class Deck {
deckId : string = "";
name : string = "";
cards : Card[] = [];
constructor() {
this.deckId = "";
this.name = "";
this.cards = [];
}
public addCards(cards: Card[]) {
this.cards.push.apply(this.cards, cards);
}
public getCards() : Card[] {
return this.cards;
}
public addCard(card : Card) {
this.cards.push(card);
}
}
//Card
export class Card {
name: string
id: string
constructor(json? : any) {
this.name = json?.name;
this.id = json?.id;
}
}
你不能调用
Array.push
,因为它会改变数组,从而改变状态,这违反了 ngrx 的基本规则之一 - 状态应该是不可变的。
您需要通过reducer以不可变的方式执行所有此类状态更改。
也不要将
currentDeck
存储为 Deck
,因为这会复制 deck
数组中存在的相同状态,这违反了单一事实来源原则 - 请改用索引。
export interface MyState {
decks: Deck[],
currentDeckIndex : number;
}
...
on(addCardToCurrentDeckActions.addCardCurrentDeckSuccess, (state, { card }) => {
// add the card to a a copy of the relevant deck
const updatedDeck = [...state.decks[currentDeckIndex], card];
// replace decks with an array that has the updated deck inserted
return {
... state,
decks: state.decks.map((deck, index) => index === currentDeckIndex ? updatedDeck : deck)
};
})