react redux добавление товара в корзину

Я делаю магазин книг. Сделал большею часть функционала по видеоуроку, но вижу магазин можно дополнить. Подскажите как сделать функцию добавление товара в корзину и чтобы был счетчик на корзине сколько добавилось товаров.

reducer разделён на 2 части.

shopping-cart.js

const updateCartItems = (cartItems, item, idx) => {

  if (item.count === 0) {
    return [
      ...cartItems.slice(0, idx),
      ...cartItems.slice(idx + 1)
    ];
  }

  if (idx === -1) {
    return [
      ...cartItems,
      item
    ];
  }

  return [
    ...cartItems.slice(0, idx),
    item,
    ...cartItems.slice(idx + 1)
  ];
};

const updateCartItem = (book, item = {}, quantity) => {

  const {
    id = book.id,
    count = 0,
    title = book.title,
    total = 0 } = item;

  return {
    id,
    title,
    count: count + quantity,
    total: total + quantity*book.price
  };
};

const updateOrder = (state, bookId, quantity) => {
  const { bookList: { books }, shoppingCart: { cartItems }} = state;

  const book = books.find(({id}) => id === bookId);
  const itemIndex = cartItems.findIndex(({id}) => id === bookId);
  const item = cartItems[itemIndex];

  const newItem = updateCartItem(book, item, quantity);
  return {
    orderTotal: 0,
    cartItems: updateCartItems(cartItems, newItem, itemIndex)
  };
};

const updateShoppingCart = (state, action) => {

  if (state === undefined) {
    return {
      cartItems: [],
      orderTotal: 0
    }
  }

  

  switch(action.type) {
    case 'BOOK_ADDED_TO_CART':
      return updateOrder(state, action.payload, 1);

    case 'BOOK_REMOVED_FROM_CART':
      return updateOrder(state, action.payload, -1);

    case 'ALL_BOOKS_REMOVED_FROM_CART':
      const item = state.shoppingCart.cartItems.find(({id}) => id === action.payload);
      return updateOrder(state, action.payload, -item.count);

    default:
      return state.shoppingCart;
  }
};

export default updateShoppingCart;

book-list.js

const updateBookList = (state, action) => {

    if (state === undefined) {
      return {
        books: [],
        loading: true,
        error: null
      };
    }
  
    switch (action.type) {
      case 'FETCH_BOOKS_REQUEST':
        return {
          books: [],
          loading: true,
          error: null
        };
  
      case 'FETCH_BOOKS_SUCCESS':
        return {
          books: action.payload,
          loading: false,
          error: null
        };
  
      case 'FETCH_BOOKS_FAILURE':
        return {
          books: [],
          loading: false,
          error: action.payload
        };
  
      default:
        return state.bookList;
    }
  };
  
  export default updateBookList;

actions index.js

const booksRequested = () => {
  return {
    type: 'FETCH_BOOKS_REQUEST'
  }
};

const booksLoaded = (newBooks) => {
  return {
    type: 'FETCH_BOOKS_SUCCESS',
    payload: newBooks
  };
};

const booksError = (error) => {
  return {
    type: 'FETCH_BOOKS_FAILURE',
    payload: error
  };
};

export const bookAddedToCart = (bookId) => {
  return {
    type: 'BOOK_ADDED_TO_CART',
    payload: bookId
  };
};

export const bookRemovedFromCart = (bookId) => {
  return {
    type: 'BOOK_REMOVED_FROM_CART',
    payload: bookId
  };
};


export const allBooksRemovedFromCart = (bookId) => {
  return {
    type: 'ALL_BOOKS_REMOVED_FROM_CART',
    payload: bookId
  };
};


const fetchBooks = (bookstoreService, dispatch) => () => {
  dispatch(booksRequested());
  bookstoreService.getBooks()
    .then((data) => dispatch(booksLoaded(data)))
    .catch((err) => dispatch(booksError(err)));
};

export {
  fetchBooks
};

на данный момент 2 товара из сервиса

export default class BookstoreService {

  
    data = [
      {
        id: 1,
        title: 'Production-Ready Microservices',
        author: 'Susan J. Fowler',
        price: 32,
        coverImage: 'https://images-na.ssl-images-amazon.com/images/I/41yJ75gpV-L._SX381_BO1,204,203,200_.jpg'},
      {
        id: 2,
        title: 'Release It!',
        author: 'Michael T. Nygard',
        price: 45,
        coverImage: 'https://images-na.ssl-images-amazon.com/images/I/414CRjLjwgL._SX403_BO1,204,203,200_.jpg'}
    ];

    getBooks() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (Math.random() > 0.75) {
            resolve(this.data);
          }
        }, 700);
      });
    }

}


Ответы (1 шт):

Автор решения: Konstantin Modin

Для добавления счетчика на корзине сколько добавилось товаров необходимо в компоненте AppHeader получать items из Redux. Далее имея товары в корзине мы можем отображать их колличество. Получается примерно так:

import React from "react";
import { useSelector } from "react-redux";
import { Link } from "react-router-dom";

import cartIcon from "./shopping-cart-solid.svg";
import "./app-header.scss";

const AppHeader = ({ total }) => {
  const items = useSelector((state) => state.items);
  console.log(`items`, items);

  const itemsInCartCount = items.length;

  return (
    <header className="header">
      <Link to={"/"} className="header__link">
        Menu
      </Link>
      <Link to="/cart" className="header__link">
        <img className="header__cart" src={cartIcon} alt="cart"></img>
        Total: {total} $
        {!!itemsInCartCount && <span> Items in cart: {itemsInCartCount}</span>}
      </Link>
    </header>
  );
};

export default AppHeader;
→ Ссылка