Home > Enterprise >  Added new key-value to object in an array fetched from an API and trying to toggle the key value, bu
Added new key-value to object in an array fetched from an API and trying to toggle the key value, bu

Time:01-05

So basically, I'm fetching products from an API and I added a new key value isAdded to the object inside the products array, I used foreach loop to add that key and its succesfully added, now when I hit Add to cart button I'm adding the product item to my <Cart /> which is also working fine but the only thing I wanna do is when that specific product to added to the Cart I wanna change the text and style of the button, which means I wanna toggle the isAdded value. But the isAdded seems undefined when I click the button, rest data is going fine but not my key.

BookProduct.js

import BookItems from "./BookItems";
import classes from "./book-item.module.css";
import { useEffect } from "react";

export default function BookProducts({ booksData }) {
    useEffect(() => {
        booksData.forEach((element) => {
            element.isAdded = false;
        });
    }, []);

    console.log(booksData); //isAdded key perfectly added in the object

    return (
        <div className="container">         
                {booksData.map((el) => {
                    return (
                        <BookItems
                            id={el.isbn13}
                            key={el.isbn13}
                            imageUrl={el.image}
                            price={Number(el.price.slice(1))}
                            title={el.title}
                            subtitle={el.subtitle}
                            link={el.link}
                            isAdded={el.isAdded}
                        />
                    );
                })}     
        </div>
    );
}

BookItems.js

import { useDispatch, useSelector } from "react-redux";
import Image from "next/image";
import Link from "next/link";
import classes from "./book-item.module.css";
import { cartStoreAction } from "../../store/cart-items";

export default function BookItems(props) {
    const { id, title, price, imageUrl, isAdded } = props;
    const dispatch = useDispatch();

    const addToCartHandler = () => {
        dispatch(
            cartStoreAction.addProduct({
                id,
                title,
                price,
                imageUrl,
                isAdded
            })
        );
        console.log(isAdded); //isAdded is undefined
    };

    return (
        <div className={classes.product__item}>
            <Link href={`/products/${id}`} className={classes.image_box}>
                <Image src={imageUrl} alt={title} className={classes.image} fill />
            </Link>
            <div className={classes.desc_box}>
                <Link href={`/products/${id}`}>
                    <h3>{title}</h3>
                </Link>
                <div className={classes.bottom}>
                    <p>${price}</p>
                    <button onClick={addToCartHandler}>
                        {isAdded ? 'Added' : 'Add to cart'}
                    </button>
                </div>
            </div>
        </div>
    );
}

cart-items.js

const cartItemSlice = createSlice({
    name: "cart",
    initialState: {
        items: [],
        totalQuantity: 0,
        totalAmount: 0,
    },
    reducers: {
        addProduct(state, action) {
            const newCartItems = action.payload; //items from dispatch object
            const existingItem = state.items.find((el) => el.id === newCartItems.id);                   
            state.totalQuantity  ;
            if (!existingItem) {
                state.items.push({
                    id: newCartItems.id,
                    quantity: 1,
                    title: newCartItems.title,
                    price: newCartItems.price,
                    image: newCartItems.imageUrl,
                    totalPrice: newCartItems.price,     
                    isAdded: !newCartItems.isAdded,
                });
                !newCartItems.isAdded;
            } else {
                existingItem.quantity  ;
                existingItem.totalPrice = existingItem.totalPrice   newCartItems.price;
            }
            state.totalAmount = state.items.reduce(
                (acc, index) => acc   Number(index.price) * Number(index.quantity),
                0
            );
        },      
    },
});

CodePudding user response:

It seems you are mutating the wrong object. Don't mutate passed props. I'd suggest skipping setting any isAdded property in the addProduct reducer function and selecting the state in the BookItems component to know if an item has been added to the cart already by the item id.

cartItemSlice

const cartItemSlice = createSlice({
  name: "cart",
  initialState: {
    items: [],
    totalQuantity: 0,
    totalAmount: 0,
  },
  reducers: {
    addProduct(state, action) {
      const { payload } = action; // items from dispatch object
      const existingItem = state.items.find((el) => el.id === payload.id);
                
      if (!existingItem) {
        state.items.push({
          quantity: 1,
          ...payload,
          totalPrice: payload.price,
        });
      } else {
        existingItem.quantity  ;
        existingItem.totalPrice  = newCartItems.price;
        isAddedToCart();
      }

      state.totalQuantity  ;
      state.totalAmount = state.items.reduce(
        (acc, index) => acc   Number(index.price) * Number(index.quantity),
        0
      );
    },
    removeProduct(state, action) {
      const removingItemId = action.payload;
      const alreadyAddedItem = state.items.find(
        (item) => item.id === removingItemId
      );
      
      if (alreadyAddedItem.quantity === 1) {
        state.items = state.items.filter((item) => item.id !== removingItemId);
      } else {
        alreadyAddedItem.quantity--;
        alreadyAddedItem.totalPrice -= alreadyAddedItem.price;
      }

      state.totalQuantity--;
      state.totalAmount = state.items.reduce(
        (acc, index) => acc   Number(index.price) * Number(index.quantity),
        0
      );
    },
  },
});

BookProducts

export default function BookProducts({ booksData }) {
  return (
    <div className="container">
      {booksData.map((el) => (
        <BookItems
          id={el.isbn13}
          key={el.isbn13}
          image={el.image}
          price={Number(el.price.slice(1))}
          title={el.title}
        />
      ))}
    </div>
  );
}

BookItems

Select the cart items from the store and check if the current BookItems id prop is a match to an element in the cart items array.

import { useDispatch, useSelector } from "react-redux";
...

export default function BookItems({ id, title, price, image }) {
  const dispatch = useDispatch();

  const cartItems = useSelector(state => state.cart.items);

  const isAdded = cartItems.some(item => item.id === id); // <-- compute here

  const addToCartHandler = () => {
    dispatch(cartStoreAction.addProduct({
      id,
      title,
      price,
      image,
    }));
  };

  return (
    <div className={classes.product__item}>
      <Link href={`/products/${id}`} className={classes.image_box}>
        <Image src={image} alt={title} className={classes.image} fill />
      </Link>
      <div className={classes.desc_box}>
        <Link href={`/products/${id}`}>
          <h3>{title}</h3>
        </Link>
        <div className={classes.bottom}>
          <p>${price}</p>
          <button onClick={addToCartHandler}>
            {isAdded ? 'Added' : 'Add to cart'}
          </button>
        </div>
      </div>
    </div>
  );
}
  • Related