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

React.js:如何实现将选中商品添加至目标卡片的功能?

修正React添加至购物卡片功能的实现

我帮你梳理下代码里的问题,然后给出修正后的实现,这样你能更清晰理解React状态管理在这个场景下的应用:

import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import { styled } from "@mui/material/styles";
import React, { useState, useEffect } from "react";

const StyledBox = styled("div")({
  paddingRight: "70px",
  paddingLeft: "70px",
  boxShadow: "rgba(100, 100, 111, 0.2) 0px 7px 29px 0px",
  backgroundColor: "#FFFFFF",
  border: "1px solid black",
  minHeight: "200px",
  paddingTop: "20px",
  paddingBottom: "20px"
});

const AddToCard = () => {
  // 分开维护商品列表和购物车列表两个独立状态
  const [products, setProducts] = useState([]);
  const [cartItems, setCartItems] = useState([]);

  // 加载商品数据
  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((res) => res.json())
      .then((result) => setProducts(result))
      .catch((e) => console.log(e));
  }, []);

  // 添加到购物车的逻辑:避免重复添加,保证状态更新的不可变性
  const addToCardHandleClick = (item) => {
    const isAlreadyInCart = cartItems.some(cartItem => cartItem.id === item.id);
    if (!isAlreadyInCart) {
      setCartItems(prevCart => [...prevCart, item]);
    }
  };

  return (
    <Card sx={{ maxWidth: 700, minHeight: "300px", margin: "20px auto" }}>
      <CardContent>
        <Box sx={{ display: "flex", gap: "30px", justifyContent: "center", overflow: "auto" }} >
          {/* 购物卡片区域:渲染已选中的商品 */}
          <StyledBox sx={{ minWidth: "200px" }}>
            <h4>购物卡片</h4>
            {cartItems.length === 0 ? (
              <p>暂无选中商品</p>
            ) : (
              cartItems.map(item => (
                <ul key={item.id} style={{ listStyle: "none", paddingLeft: 0 }}>
                  <li>{item.name}</li>
                </ul>
              ))
            )}
          </StyledBox>
          
          {/* 如果需要实现「选中单个商品后点击Move」的逻辑,可在这里加选中状态和Move按钮,我后面会补充示例 */}
          <Box sx={{ alignSelf: "center", gap: "10px" }} >
          </Box>
          
          {/* 商品列表区域:每个商品配独立的添加按钮 */}
          <StyledBox>
            <h4>商品列表</h4>
            {products.length > 0 ? (
              products.map((item) => (
                <div key={item.id} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "10px" }}>
                  <ul style={{ listStyle: "none", paddingLeft: 0, margin: 0 }}>
                    <li>{item.name}</li>
                  </ul>
                  <Button 
                    variant="outlined" 
                    onClick={() => addToCardHandleClick(item)}
                  > 
                    添加至购物卡 
                  </Button>
                </div>
              ))
            ) : (
              <p>加载中...</p>
            )}
          </StyledBox>
        </Box>
      </CardContent>
    </Card>
  );
};

export default AddToCard;

关键修改点说明:

  • 拆分状态:把原来单一的data拆成products(商品列表)和cartItems(购物车列表),避免两个列表的数据互相干扰,符合React状态管理的单一职责原则。
  • 修正添加逻辑:用some方法检查购物车是否已有该商品,避免重复添加;通过扩展运算符...prevCart更新状态,保证状态的不可变性(React状态更新的最佳实践)。
  • 完善渲染内容:左边的购物卡片区域现在会根据cartItems动态渲染内容,空状态时显示友好提示。
  • 优化交互体验:给每个商品单独配置添加按钮,交互逻辑更直观,也更容易理解流程。

如果想要实现你最开始描述的「选中商品后点击统一Move按钮」的逻辑,可以补充以下代码:

// 新增选中商品的状态
const [selectedItem, setSelectedItem] = useState(null);

// 修改商品列表的渲染,添加选中样式
products.map((item) => (
  <div 
    key={item.id} 
    style={{ 
      display: "flex", 
      justifyContent: "space-between", 
      alignItems: "center", 
      marginBottom: "10px",
      border: selectedItem?.id === item.id ? "1px solid blue" : "none",
      padding: "5px",
      cursor: "pointer"
    }}
    onClick={() => setSelectedItem(item)}
  >
    <ul style={{ listStyle: "none", paddingLeft: 0, margin: 0 }}>
      <li>{item.name}</li>
    </ul>
  </div>
))

// Move按钮的点击逻辑
const handleMoveClick = () => {
  if (selectedItem) {
    const isAlreadyInCart = cartItems.some(cartItem => cartItem.id === selectedItem.id);
    if (!isAlreadyInCart) {
      setCartItems(prevCart => [...prevCart, selectedItem]);
    }
    setSelectedItem(null); // 清空选中状态
  }
}

// 在中间的Box里渲染Move按钮
<Button 
  variant="outlined" 
  onClick={handleMoveClick}
  disabled={!selectedItem}
> 
  Move 
</Button>

这样就完全实现了你想要的「选中商品→点击Move按钮→商品进入购物卡片」的完整流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 01:17:48