Search code examples
javascriptreactjsredux

Reducer function in redux gets called multiple times


Please someone make me understand the underlying behavior of redux. Here is my reducer function with one case:

  case INCREASE_QTY:
      return state.map((product) => {
        if (product.id === action.payload.id) {
          return {
            ...product,
            data: {
              ...product.data,
              qty: product.data.qty + action.payload.qty,
            },
          };
        }
        console.log('hello')
        return product;
      });

In above case, I was mistakenly returning state instead of product outside the if block. This was causing unexpected behavior.

action creator:

export const increaseQty = (id, qty) => {
  return {
    type: INCREASE_QTY,
    payload: {
      id,
      qty,
    },
  };
};

and dispatching action:

import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { increaseQty } from '../redux/productSlice/actions';
import { deleteFromCart } from '../redux/cartSlice/actions';

const CartCard = ({ product }) => {
  const cart = useSelector((state) => state.cart);
  const dispatch = useDispatch();

  const deleteHandler = (id) => {
    const correspondingProduct = cart.productInfo.find(
      (product) => product.id === id
    );

    dispatch(deleteFromCart(correspondingProduct.id));
    dispatch(increaseQty(correspondingProduct.id, correspondingProduct.qty));
  };

  return (
    <div className="cartCard">
      <div className="flex items-center col-span-6 space-x-6">
        <img className="cartImage" src={product.data.image} alt="product" />

        <div className="space-y-2">
          <h4 className="cartName">{product.data.name}</h4>
          <p className="cartCategory">{product.data.category}</p>
          <p>
            BDT <span className="cartPrice">{product.data.price}</span>
          </p>
        </div>
      </div>

      <div className="flex items-center justify-center col-span-2 mt-4 md:justify-end md:mt-0">
        <button
          className="removeFromCart"
          onClick={() => deleteHandler(product.id)}
        >
          <i className="text-lg text-red-400 fa-solid fa-trash"></i>
        </button>
      </div>
    </div>
  );
};

export default CartCard;

My question is, if I have multiple products in cart and wanna delete an item, the unexpected behavior was it was deleting all items. However I found that I was doing wrong in the reducer function. But I want to understand, if the ID matches, hello should not pe printed on the console. And thus the unexpected behavior would not happen. But in this case, console.log() is being called though the if block is executed. Why? Thanks in advance.


Solution

  • Array.prototype.map() runs for all the elements of the array. The return statement is not used to break out of the loop, as you are expecting. It is used to transform an element of an array and return a new element.

    The reducer for the INCREASE_QTY will do this:

    It will run the callback for all elements of state and transform the one where id matches, and return rest all products as it is.