chrus54321
chrus54321

Reputation: 125

Increment value of array of objects redux

I need to increment quantity of item in cart if item already exists in the state array. In the reducer I got it to work but it needs to be immutable. Because of this, my component doesnt update properly.

This is the code for my reducer:

import { ADD_TO_CART, REMOVE_FROM_CART } from '../actions/types';

const initialState = [];

//Cannot mutate array in reducer 

export default function(state = initialState, action){
    const { type, payload } = action;

    switch(type){
        case ADD_TO_CART:
            const newState = [...state]
            for(var i = 0; i < newState.length; i++){
                if(newState[i].item.uid === payload.item.uid){
                    newState[i].item.qty ++;
                    return [...newState];
                }
            }
            return [...state, payload];
        case REMOVE_FROM_CART:
            for(var j = 0; j < state.length; j++){
                    if(state[j].item.uid === payload.uid){
                        state[j].item.qty = 1;
                    }
            }
            return state.filter(cartItem => cartItem.item.uid !== payload.uid);

        default:
            return state;
    }
}

I need to increment qty if item is already in the array.

Upvotes: 1

Views: 1706

Answers (1)

Drew Reese
Drew Reese

Reputation: 202686

The issue I see is with newState[i].item.qty++;, that although you shallowly copied the array, the elements in the array still represent those of the previous state, so post incrementing it mutates the object.

To resolve this issue you should also copy each item into a new object, then update the new object reference.

The following also include a minor optimization to iterate the data once versus twice, by checking for the matching item ID as it copying the state into a new array.

let itemExists = false;
const newState = state.map(item => {
  const newItem = { ...item };
  if (newItem.item.uid === payload.item.uid) {
    itemExists = true;
    newItem.item.qty = item.qty + 1;
  }
  return newItem;
});

if (!itemExists) newState.push(payload);

return newState;

EDIT: Alternative method

const itemIndex = state.findIndex(item => item.item.id === payload.item.id);
if (itemIndex !== -1) {
  return state.map((item, i) => ({
    ...item,
    item: {
      ...item.item,
      qty: item.item.qty + (itemIndex === i ? 1 : 0),
    }
  }));
} else {
  return [...state, payload];
}

Upvotes: 1

Related Questions