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

React点击删除按钮后购物车组件重复渲染问题求助

React购物车删除商品后重复渲染问题

我是React新手,正在制作电商网站用于练习。购物车组件从API动态渲染购物车商品,已100%确认问题出在前端。初始渲染时一切正常,数据库中的购物车内容均可正常显示,但点击购物车商品上的“Remove From Cart”按钮后,每个购物车商品都会重复显示。


相关组件代码

CartCard.jsx

(/api/delete 返回删除后的购物车JSON对象,删除逻辑由API处理)

import React from "react";
import CartCardCSS from "./CartCard.module.css";

export default function CartCard(props) {
    const passCart = props.passCart;

    function deleteFromCart(e) {
        e.preventDefault();

        const item = {
            id: props.id,
            mainText: props.mainText,
            price: props.price,
            type: props.type
        }
        const user = {
            username: props.username
        }
        const compoundEntity = {
            theContent: item,
            theUser: user
        }

        const requestOptions = {
            method: "POST",
            headers: {"Content-Type" : "application/json"},
            body: JSON.stringify(compoundEntity)
        }

        fetch("/api/delete", requestOptions)
        .then(response => response.json())
        .then(response => {
            passCart(response)
            console.log(response)
        })
    }
    
    return (
        <div className={CartCardCSS.card}>
            <img src={props.image} className={CartCardCSS.itempicture} alt="item picture"/>
            <h3 className={CartCardCSS.subitem}>{props.mainText}</h3>
            <h4 className={CartCardCSS.subitem}>{props.price}</h4>
            <button onClick={deleteFromCart} className={`${CartCardCSS.subitem} ${CartCardCSS.button}`} type="button">Remove From Cart</button>
        </div>
    )
}

Cart.jsx

import React, {useEffect, useState} from "react";
import CartCard from "./CartCard";

import CpuPicture from "./img/cpu.jpg";
import GpuPicture from "./img/gpu.jpg";

export default function Cart(props) {
    const cart = props.cart;
    const username = props.username;
    const passCart = props.passCart;
    const [arrCart, setArrCart] = useState(Object.values(cart))
    const [cartComp, setCartComp] = useState()

    useEffect(() => {
        console.log(cart)
        setArrCart(Object.values(cart))
    
        for(let i = 0; i < arrCart.length; i++) {
            setCartComp(arr => [arr, <CartCard key={i} id={i} passCart={passCart} username={username} mainText={arrCart[i].mainText} price={arrCart[i].price} type={arrCart[i].type} image={arrCart[i].type === "cpu" ? CpuPicture : GpuPicture}/>])
        }
    }, [cart])

    return (
        <div>
            <h2 >Cart:</h2>
            {cartComp}
        </div>
    )
}

Profile.jsx

import React from "react";
import Cart from "./Cart";
import Navbar from "./Navbar";

import {useNavigate} from "react-router-dom";

export default function Profile(props) {
    const username = props.username;
    const isLoggedIn = props.isLoggedIn;
    const cart = props.cart;
    const passCart = props.passCart;
    let navigate = useNavigate();
    const routeChange = () => {
        let path = "/login";
        navigate(path);
    }

    if (isLoggedIn) {
        return (
            <div>
                <Navbar />
                <h1>{username}</h1>
                <Cart passCart={passCart} username={username} cart={cart} />
            </div>
        )
    } else {
        routeChange();
    }
}

App.jsx

import React, {useState} from "react";
import './App.css';
import Login from "./components/Login";
import Signup from "./components/Signup";
import Home from "./components/Home";
import Profile from "./components/Profile";
import Card from "./components/Card";
import GpuPicture from "./components/img/gpu.jpg";
import CpuPicture from "./components/img/cpu.jpg";

import {BrowserRouter, Routes, Route, Navigate} from "react-router-dom";

function App() {
  const [username, setUsername] = useState('');
  const [cart, setCart] = useState('');
  const [isLoggedIn, setIsLoggedIn] = useState(false)

  function passUsername(items) {
    setUsername(items);
  }
  function passCart(items) {
    setCart(items);
  }
  function passIsLoggedIn(items) {
    setIsLoggedIn(items);
  }

  return (
    <div className="App">
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<Navigate to="/login"/>} />
          <Route path="/login" element={<Login passIsLoggedIn={passIsLoggedIn} passUsername={passUsername} passCart={passCart}/>}/>
          <Route path="/signup" element={<Signup />}/>
          <Route path="/home" element={<Home passCart={passCart} cart={cart} username={username} isLoggedIn={isLoggedIn} />} />
          <Route path="/profile" element={<Profile passCart={passCart} cart={cart} username={username} isLoggedIn={isLoggedIn}/>} />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;

问题根源及修复方案

核心问题

Cart.jsx中存在两个关键错误:

  1. 状态更新逻辑错误:在useEffect里循环调用setCartComp时,每次都是将新组件追加到旧数组中,且arrCart的更新是异步的,导致每次删除操作后都会累加渲染旧的组件,造成重复显示。
  2. key值使用不当:用循环索引i作为组件的key,React无法正确识别组件的增减,会导致渲染异常。

修复后的Cart.jsx

import React, { useEffect, useState } from "react";
import CartCard from "./CartCard";

import CpuPicture from "./img/cpu.jpg";
import GpuPicture from "./img/gpu.jpg";

export default function Cart(props) {
    const { cart, username, passCart } = props;
    const [arrCart, setArrCart] = useState(Object.values(cart));

    // 监听cart变化,同步更新arrCart
    useEffect(() => {
        setArrCart(Object.values(cart));
    }, [cart]);

    // 直接在渲染阶段生成购物车组件列表,无需维护cartComp状态
    const cartItems = arrCart.map((item) => (
        <CartCard
            key={item.id} // 使用商品自身的唯一id作为key,不要用索引
            id={item.id} // 传递商品真实id,确保删除逻辑正确
            passCart={passCart}
            username={username}
            mainText={item.mainText}
            price={item.price}
            type={item.type}
            image={item.type === "cpu" ? CpuPicture : GpuPicture}
        />
    ));

    return (
        <div>
            <h2>Cart:</h2>
            {cartItems}
        </div>
    );
}

额外优化

App.jsx中cart的初始状态应设为空对象,避免初始时Object.values(cart)处理空字符串出错:

const [cart, setCart] = useState({});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 00:21:41