将对象添加到 NgRx reducer 中 state 中包含的另一个对象中的子对象数组中

Add object to child object array in another object contained in state within an NgRx reducer

提问人:Nayrb 提问时间:10/15/2023 更新时间:10/16/2023 访问量:31

问:

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

在我的情况下,我有包含对象数组 Card[] 的 Deck 对象。您可以在我的状态对象 currentDeck 中看到这一点。

我发现任何在化简器外部操作currentDeck的尝试都会导致错误“can't define array index property past the end of an array of an un-writable length”。这让我意识到,经过一些研究,我需要在减速器中正确地做到这一点。

我有一个 NgRx 效果,它调度一个成功操作 addCardCurrentDeckSuccess,该操作将一张新卡添加到牌组中。这不仅需要更改卡牌阵列,还需要更改我假设的套牌。我调度的操作传入了需要添加到当前甲板对象 Card[] 的卡片中。

我在 Deck 对象中有一个 addCard 方法,我认为解决方案中需要它。

我的代码和数据结构如下。我已经删除了大多数不相关的变量和其他 reducer 操作。

目前,我正在寻找一种不需要安装“浸入式”模块的解决方案。我已经做了一些标准化数据集的阅读,但我不确定我如何在这里做到这一点。

任何帮助将不胜感激。

我的状态和 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;
    }
}
角度 状态 ngrx reduce ngrx-store

评论


答:

2赞 wlf 10/16/2023 #1

你不能调用,因为它会改变数组,从而改变状态,这违反了 ngrx 的基本规则之一——状态应该是不可变的。Array.push

您需要通过 reducer 以不可变的方式执行所有这些状态更改。

也不要存储为 a,因为这会复制数组中存在的相同状态,这违反了单一事实来源原则 - 请改用索引。currentDeckDeckdeck

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)  
  }; 
})