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
相关产品推荐
相关产品推荐

