Home > Enterprise >  Edit(Mutate) object property inside a reducer in NgRx
Edit(Mutate) object property inside a reducer in NgRx

Time:07-07

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.

CodePudding user response:

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

CodePudding user response:

It is not recommended to change the payload inside reducers as they are intended to be pure functions. I would recommend you to update the payload before dispatching as shown below. Once dispatched, you should not be worrying about editing payload

addPokemon(pokemon: any) {
  pokemon.isAdded = true;
  this.store.dispatch(addToCart({ pokemon }));
}
  • Related