Search code examples
angularfunctional-programmingngrx

Edit(Mutate) object property inside a reducer in NgRx


I'm having troubles when trying to edit a property inside an object. I'm using PokeApi to fetch Pokémon and then, with a button, add them into a cart.

Interface

export interface PokemonModel {
  name: string;
  url: string;
  quantity: number;
  isAdded: boolean;
}

Action

export const addToCart = createAction(
  '[Cart List] Add To cart',
  props<{ pokemon: PokemonModel }>()
);

Reducer

on(addToCart, (state, { pokemon }) => {
  pokemon.isAdded = true; // <-- Cannot add property isAdded, object is not extensible

  return {
    ...state,
    loading: false,
    error: false,
    pokemons: [
      ...state.pokemons.filter((pk) => pk.name !== pokemon.name),
      ...[pokemon],
    ],
  };
}),

Function

addPokemon(pokemon: any) {
  this.store.dispatch(addToCart({ pokemon }));
}

The thing is, I need to edit the value for isAdded property.

I have tried with Object.preventExtensions(pokemon) no matter if I add above or below the property, the result is the same.


Solution

  • Small reminder: Because reducers are pure functions you can't mutate the state manually, you need to create a copy and edit the copy (this is all functional programming princicples.

    Create a copy of Pokémon:

    let pokemonCopy = {...pokemon, isAdded: true}
    

    And for the spread operator, you're combining both computed property in objects and spread operator at the same time, which I don't think it's gonna work for you.

    You need to simply append it to the new state

     return {
        ...state,
        loading: false,
        error: false,
        pokemons: [
          ...state.pokemons.filter((pk) => pk.name !== pokemon.name),
          pokemonCopy,
        ],
      };
    

    and if the order matter to you, I'd recommend

    return {
        ...state,
        loading: false,
        error: false,
        pokemons: [
          ...state.pokemons.map((pk) => pk.name == pokemon.name ? pokemonCopy : pk),
        ],
      };