reactjsreduxreducers

Update object property in array of objetcs in reducer - Redux


Hey everyone I am trying to find the best way to update a property value of an object inside an array of objects, without mutating the array, inside my reducer.

Here is my reducer file :

const initialState = {
    products:[]
};

export default function basketReducer(state = initialState, action){
    switch (action.type) {
        case "ADD_PRODUCT_TO_BASKET":
            return state
        case "REMOVE_PRODUCT_FROM_BASKET":
            return state
        default:
            return state
    }
};

Here is an example of a product object :

{
     id: 1,
     name: "product 1",
     quantity: 1,
     price: 1.0,
}

When I add a product that is already in my array (same id), I want to increment his quantity property by one. I already have the function to check if the item already exists in my array, I am just searching for a way to update the quantity property without mutating the array.

Thanks for the help!

UPDATE : According to the answer of @Will Jenkins i wrote this code :

case "ADD_PRODUCT_TO_BASKET": {
            const index = state.products.findIndex(p => p.id === action.payload.id);
            if(index !== -1){
                const productId = action.payload.id
                return {...state, products: state.products.map(p => p.id === productId ? {...p, quantity:p.quantity+1} : p)}
            }else {
                return {products: [...state.products].concat(action.payload)};
            }
        }

This is working well, when I add a new product there is appended to the array and if I add the same product his quantity is incremented by one, but I am pretty sure I can refactor this code, does anyone have a proposition?


Solution

  • Assuming you're passing the product id as the payload of your action, map over your products and increment the quantity of the one that matches the id:

    case "ADD_PRODUCT_TO_BASKET": {
            const productId = payload
            return {...state, products: state.products.map(p => p.id === productId ? {...p, quantity:p.quantity+1} : p)}
    }
    

    Update

    I'd go for something a bit more long-form so it's easier for others (or future you) to understand and maintain:

    case "ADD_PRODUCT_TO_BASKET": {
        const addedProduct = action.payload;
        const productId = addedProduct.id;
        const exists = state.products.some((p) => p.id === productId);
        if (exists) {
          const products = state.products.map((p) =>
            p.id === productId ? { ...p, quantity: p.quantity + 1 } : p
          );
          return { ...state, products };
        } else {
          return {
            ...state,
            products: [...state.products, { ...addedProduct }]
          };
        }
      }