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