将对象添加到 NgRx 减速器内状态中包含的另一个对象的子对象数组中

问题描述 投票:0回答:1

我无法找出将新对象添加到状态块中包含的数组的正确语法。该数组是另一个对象的一部分,也是我状态的一部分。

在我的情况下,我有 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;
    }
}
angular state ngrx reduce ngrx-store
1个回答
0
投票

你不能调用

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)  
  }; 
})
© www.soinside.com 2019 - 2024. All rights reserved.