You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中LocalStorage购物车增删改功能实现咨询(附代码)

购物车数量更新与删除功能实现方案

我是Arslan Chaudhry,正在开发一个电商网站,因为缺乏后端知识,选择用LocalStorage存储购物车数据。目前已经在Books.js中完成了商品添加到购物车的功能,现在需要在Cart.js中实现商品数量增减和删除功能,以下是我的现有代码:

Books.js 代码

import React from "react";
import "./components/book.css";
import Carousel from "react-multi-carousel";
import "react-multi-carousel/lib/styles.css";
import { FaShoppingCart } from "react-icons/fa";
import { useEffect } from "react";
import { useState, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { createContext } from "react";
const Books = () => {
  let arr=()=>{
    let dat=localStorage.getItem("products")
    if (dat) {
      return JSON.parse(dat)
    }
    else{
      return []
    }
  }
  const [booksData, setbooksData] = useState([]);
  const [productData, setproductData] = useState(arr());

 
  
  let nav = useNavigate();
  // slider 
  const responsive = {
    superLargeDesktop: {
      breakpoint: { max: 4000, min: 3000 },
      items: 5,
    },
    desktop: {
      breakpoint: { max: 3000, min: 1024 },
      items: 3,
    },
    tablet: {
      breakpoint: { max: 1024, min: 464 },
      items: 2,
    },
    mobile: {
      breakpoint: { max: 464, min: 0 },
      items: 1,
    },
  };
  let croser = useRef("");
  let loding = useRef("");
  
  const getJason = async () => {
    try {
      let fea = await fetch(
        "https://script.google.com/macros/s/AKfycbxFCG7S-kjncQZwvcMnqq4wXoBAX8ecH1zkY2bLP7EE-YHlnKbiJ3RUuHtWLe6sIK30Kw/exec"
      );
      let acData = await fea.json();
      let itemsData = acData.shop.filter((element) => {
        if (element.name) {
          return element;
        }
      });
      setbooksData(itemsData);

      if (itemsData) {
        croser.current.style.filter = "blur(0px)";
        loding.current.style.display = "none";
      }
    } catch (error) {
   
      croser.current.style.filter = "blur(0px)";
      loding.current.style.display = "none";
    }
  };
  // get product data from api
  useEffect(() => {
    getJason();
  }, []);
  // go to cart button
  const goto = () => {
    nav("/Cart");
  };
// local data
let addNow=(e)=>{
let data=productData.find((element)=>{return element.id === e.id });
let cart;
if (data) {
  cart=productData.map((element)=>{
  return  element.id === e.id ? {...element, quantity:element.quantity+1}:element
  })
  
}
else{
  cart=[...productData,{...e, quantity:1}]
}
setproductData(cart);
};
useEffect(() => {
  localStorage.setItem("products",JSON.stringify(productData))
  
}, [productData])
console.log(productData);
  return (
    <>
      <div className="row " style={{ marginTop: "10px" }}>
        <div className="col-lg-12 col-md-12 col-sm-12 col-xs-12">
          <div className="section-headline text-center">
            <h2>Books Shop</h2>
          </div>
        </div>
      </div>

      <div className="lodingBooks" ref={loding}>
        <div class="spinner-border" role="status"></div>
        <h4>Please wait....</h4>
      </div>

      <div ref={croser}>
        <div className=" shadow go_to_cart" onClick={goto}>
          <i class="bi bi-cart-check text-white"></i>
        </div>

        <Carousel responsive={responsive} className="container">
          {booksData.map((element) => {
            return (
              <>
                <div class="container page-wrapper">
                  <div class="page-inner">
                    <div class="row">
                      <div class="el-wrapper">
                        <div class="box-up">
                          <img class="img" src={element.images} alt="" />
                          <div class="img-info">
                            <div class="info-inner">
                              <span class="p-name text-info">
                                {element.name}
                              </span>
                              <span class="p-company ">Author:CHAUDHRY</span>
                            </div>
                            <div class="a-size ">
                              About:This is a complete book on javascript
                              <span class="size"></span>
                            </div>
                          </div>
                        </div>
                        <input
                          type="text"
                          value={1}
                          style={{ display: "none" }}
                        />
                        <div class="box-down">
                          <div class="h-bg">
                            <div class="h-bg-inner"></div>
                          </div>

                          <a class="cart">
                            <span class="price">{element.price + "$"}</span>

                            <span
                              class="add-to-cart btn btn-sm"
                              style={{ backgroundColor: "#3EC1D5" }}
                              onClick={()=>{addNow(element)}}
                            >
                              <span class="txt">
                                ADD TO CART <FaShoppingCart />
                              </span>
                            </span>
                          </a>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </>
            );
          })}
        </Carousel>
      </div>
    </>
  );
};

export default Books;

待修改的Cart.js代码

我需要在这个文件中实现商品数量更新和删除功能:

import React from "react";
import "./components/cart.css";
import { useEffect } from "react";
const Cart = () => {
  let data = localStorage.getItem("products");
  let javaData = JSON.parse(data);
  let removeData = (e) => {
    
   
  };
useEffect(() => {
  localStorage.clear()
}, [])

  return (
    <>
      <div class="container mt-5 mb-5">
        <div class="d-flex justify-content-center row">
          <div class="col-md-8">
            <div class="p-2 shoingTitle">
              <h4>Shop Now</h4>
              <span class="text-danger">Remove all</span>
            </div>
            {javaData ? (
              javaData.map((item) => {
                return (
                  <>
                    <div class="d-flex flex-row justify-content-between align-items-center p-2 bg-white mt-4 px-3 rounded">
                      <div class="mr-1 imageandpara">
                        <img class="rounded" src={item.images} width="70" />
                        <span class="font-weight-bold">{item.name}</span>
                      </div>
                      <div class="d-flex flex-column align-items-center product-details">
                        <div class="d-flex flex-row product-desc"></div>
                      </div>
                      <div class="d-flex flex-row align-items-center qty">
                        <i class="minusSign shadow">
                          <i class="bi bi-dash"></i>
                        </i>
                        <span class="text-grey quantityNumber">
                          {item.quantity}
                        </span>
                        <i class="minusSign shadow">
                          <i class="bi bi-plus"></i>
                        </i>
                      </div>
                      <div>
                        <span class="text-grey productAmount">{`${
                          item.quantity * item.price
                        }$`}</span>
                      </div>
                      <div
                        class="d-flex align-items-center text-dark "
                        style={{
                          cursor: "pointer",
                          fontWeight: "900",
                          fontSize: "15px",
                        }}
                        onClick={() => {
                          removeData(item);
                        }}
                      >
                        <i class="bi bi-x text-danger"></i>
                      </div>
                    </div>
                  </>
                );
              })
            ) : (
              <h3 style={{ textAlign: "center" }}>Cart is empety</h3>
            )}

            <div class="d-flex flex-row align-items-center mt-3 p-2 bg-white rounded">
              <input
                type="text"
                class="form-control gift-card "
                placeholder="discount code/gift card"
              />
              <button
                class="btn  btn-sm ml-3 shadow"
                type="button"
                style={{
                  outline: "#3EC1D5",
                  backgroundColor: "#3EC1D5",
                  color: "white",
                }}
              >
                Apply
              </button>
            </div>
            <div class="totalItems">
              Total Items: <strong>12</strong>
            </div>
            <span class="TotalPrice">
              Total price: <strong>12$</strong>
            </span>
            <div class="d-flex flex-row align-items-center mt-3 p-2 bg-white rounded">
              <button
                class="btn  btn-block btn-sm ml-2 pay-button shadow"
                type="button"
                style={{ backgroundColor: "#3EC1D5" }}
              >
                Proceed to Pay
              </button>
            </div>
          </div>
        </div>
      </div>
    </>
  );
};

export default Cart;

修改后的Cart.js(实现完整功能)

import React, { useState, useEffect } from "react";
import "./components/cart.css";

const Cart = () => {
  // 从LocalStorage初始化购物车数据
  const [cartItems, setCartItems] = useState(() => {
    const saved = localStorage.getItem("products");
    return saved ? JSON.parse(saved) : [];
  });

  // 同步购物车数据到LocalStorage
  useEffect(() => {
    localStorage.setItem("products", JSON.stringify(cartItems));
  }, [cartItems]);

  // 更新商品数量(增减)
  const updateQuantity = (itemId, change) => {
    setCartItems(prevItems => {
      return prevItems.map(item => {
        if (item.id === itemId) {
          // 数量不能小于1
          const newQuantity = Math.max(item.quantity + change, 1);
          return { ...item, quantity: newQuantity };
        }
        return item;
      });
    });
  };

  // 删除单个商品
  const removeItem = (itemId) => {
    setCartItems(prevItems => prevItems.filter(item => item.id !== itemId));
  };

  // 清空购物车
  const removeAll = () => {
    setCartItems([]);
  };

  // 计算总数量
  const totalItems = cartItems.reduce((sum, item) => sum + item.quantity, 0);
  // 计算总价
  const totalPrice = cartItems.reduce((sum, item) => sum + (item.quantity * item.price), 0);

  return (
    <>
      <div className="container mt-5 mb-5">
        <div className="d-flex justify-content-center row">
          <div className="col-md-8">
            <div className="p-2 shoingTitle d-flex justify-content-between align-items-center">
              <h4>Shop Now</h4>
              <span 
                className="text-danger" 
                style={{ cursor: "pointer" }}
                onClick={removeAll}
              >
                Remove all
              </span>
            </div>
            {cartItems.length > 0 ? (
              cartItems.map((item) => {
                return (
                  <div 
                    key={item.id}
                    className="d-flex flex-row justify-content-between align-items-center p-2 bg-white mt-4 px-3 rounded"
                  >
                    <div className="mr-1 imageandpara d-flex align-items-center">
                      <img className="rounded" src={item.images} width="70" />
                      <span className="font-weight-bold ml-2">{item.name}</span>
                    </div>
                    <div className="d-flex flex-column align-items-center product-details">
                      <div className="d-flex flex-row product-desc"></div>
                    </div>
                    <div className="d-flex flex-row align-items-center qty">
                      <i 
                        className="minusSign shadow" 
                        style={{ cursor: "pointer" }}
                        onClick={() => updateQuantity(item.id, -1)}
                      >
                        <i className="bi bi-dash"></i>
                      </i>
                      <span className="text-grey quantityNumber mx-2">
                        {item.quantity}
                      </span>
                      <i 
                        className="minusSign shadow" 
                        style={{ cursor: "pointer" }}
                        onClick={() => updateQuantity(item.id, 1)}
                      >
                        <i className="bi bi-plus"></i>
                      </i>
                    </div>
                    <div>
                      <span className="text-grey productAmount">{`${
                        item.quantity * item.price
                      }$`}</span>
                    </div>
                    <div
                      className="d-flex align-items-center text-dark "
                      style={{
                        cursor: "pointer",
                        fontWeight: "900",
                        fontSize: "15px",
                      }}
                      onClick={() => removeItem(item.id)}
                    >
                      <i className="bi bi-x text-danger"></i>
                    </div>
                  </div>
                );
              })
            ) : (
              <h3 style={{ textAlign: "center", marginTop: "2rem" }}>购物车为空</h3>
            )}

            <div className="d-flex flex-row align-items-center mt-3 p-2 bg-white rounded">
              <input
                type="text"
                className="form-control gift-card "
                placeholder="折扣码/礼品卡"
              />
              <button
                className="btn  btn-sm ml-3 shadow"
                type="button"
                style={{
                  outline: "#3EC1D5",
                  backgroundColor: "#3EC1D5",
                  color: "white",
                }}
              >
                应用
              </button>
            </div>
            <div className="totalItems mt-2">
              总商品数: <strong>{totalItems}</strong>
            </div>
            <span className="TotalPrice d-block mt-2">
              总价: <strong>{totalPrice}$</strong>
            </span>
            <div className="d-flex flex-row align-items-center mt-3 p-2 bg-white rounded">
              <button
                className="btn  btn-block btn-sm ml-2 pay-button shadow"
                type="button"
                style={{ backgroundColor: "#3EC1D5", color: "white" }}
              >
                去结算
              </button>
            </div>
          </div>
        </div>
      </div>
    </>
  );
};

export default Cart;

关键修改说明

  • 用useState管理购物车数据,确保数据变化时组件能重新渲染,替代原来直接读取LocalStorage的方式
  • 添加updateQuantity函数:处理商品数量的增减,限制数量不低于1
  • 添加removeItem函数:通过商品ID过滤数组,删除对应商品
  • 添加removeAll函数:直接清空购物车数组
  • 用useEffect同步购物车状态到LocalStorage,确保刷新页面后数据不丢失
  • 修复了原代码中useEffect自动清空LocalStorage的错误
  • 计算并显示真实的总商品数和总价,替代原来的固定值
  • 给增减按钮、删除按钮、清空全部按钮添加了点击事件绑定
  • 给每个购物车项添加了key属性,符合React列表渲染要求

内容的提问来源于stack exchange,提问作者arslan_chaudhry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 01:55:21