reactjsreduxreselectredux-selector

Getting the following error - TypeError: cartItems.reduce is not a function


I'm trying to count the number of items in an array called cartItems with the reduce function. But it throws off this weird error every time. My selectors code for redux -

import { createSelector } from 'reselect';

const selectCart = state => state.cart;

export const selectCartItems = createSelector(
  [selectCart],
  cart => cart.cartItems
);

export const selectCartHidden = createSelector(
  [selectCart],
  cart => cart.hidden
);

export const selectCartItemsCount = createSelector(
  [selectCartItems],
  cartItems =>
    cartItems.reduce(
      (accumalatedQuantity, cartItem) =>
        accumalatedQuantity + cartItem.quantity,
      0
    )
);

The component where I'm using the selector is below. I'm not destructuring it in the mapStateToProps function but directly passing the selector.

import React from 'react';
import { connect } from "react-redux";
import { toggleCartHidden } from "../../Redux/cart/cart.actions";
import { selectCartItemsCount } from '../../Redux/cart/cart.selectors';
import { ReactComponent as ShoppingIcon } from '../../assets/shopping-bag.svg';
import './cart-icon.styles.css';

const CartIcon = ({ itemCount, toggleCartHidden }) => (
    <div className='cart-icon' onClick={toggleCartHidden}>
        <ShoppingIcon className='shopping-icon' />
        <span className='item-count'>{itemCount}</span>
    </div>
);

const mapStateToProps = state => ({
    itemCount: selectCartItemsCount(state)
});

const mapDispatchToProps = dispatch => ({
    toggleCartHidden: () => dispatch(toggleCartHidden())
});

export default connect(
    mapStateToProps, 
    mapDispatchToProps)
(CartIcon);

This is the cart reducer -

import CartActionTypes from './cart.types';
import { addItemToCart } from './cart.utils';

const INITIAL_STATE = {
  hidden: true,
  cartItems: []
};

const cartReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case CartActionTypes.TOGGLE_CART_HIDDEN:
      return {
        ...state,
        hidden: !state.hidden
      };
    case CartActionTypes.ADD_ITEM:
      return {
        ...state,
        cartItems: addItemToCart(state.cartItems, action.payload)
      };
    default:
      return state;
  }
};

export default cartReducer;

Cart utility function -

export const addItemToCart = (cartItems, cartItemToAdd) => {
    const existingCartItem = cartItems.find(
      cartItem => cartItem.id === cartItemToAdd.id
    );
  
    if (existingCartItem) {
      return cartItems.map(cartItem =>
        cartItem.id === cartItemToAdd.id
          ? { ...cartItem, quantity: cartItem.quantity + 1 }
          : cartItem
        )
    }
  
    return [...cartItems, { ...cartItemToAdd, quantity: 1 }];
  };

enter image description here


Solution

  • If cardItems is null or undefined, cardItems.reduce will trigger that error.

    Using cartItems || [] would be solution.

    export const selectCartItemsCount = createSelector(
      [selectCartItems],
      cartItems =>
        (cartItems || []).reduce(
          (accumalatedQuantity, cartItem) =>
            accumalatedQuantity + cartItem.quantity,
          0
        )
    );