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

如何仅使用useState更新被点击的元素

解决单个产品加入购物车图标独立显示加载状态的问题

你当前的问题是用了一个全局的loading状态控制所有产品的图标,导致任何一个图标被点击时,所有图标都会同步切换成加载动画。要实现单个元素独立状态,不需要静态数组,只需要跟踪正在加载的产品ID即可。

修改方案

  1. 将全局的loading状态改为存储正在加载的产品ID集合(用Set可方便添加/移除操作)
  2. 点击时将当前产品ID加入集合,定时器结束后移除该ID
  3. 渲染时根据当前产品ID是否在集合中,决定显示加载动画还是购物车图标

修改后的完整代码

import React, { useState } from "react";
import { FiShoppingCart } from "react-icons/fi";

const Carpet = ({ products, onAddToCart }) => {
  // 用Set存储正在加载的产品ID,支持同时多个产品加载
  const [loadingIds, setLoadingIds] = useState(new Set());

  const handleAddToCart = (carpetId) => {
    // 添加当前产品ID到加载集合
    setLoadingIds(prev => new Set([...prev, carpetId]));
    // 模拟异步操作完成后移除ID
    const timer = setTimeout(() => {
      setLoadingIds(prev => {
        const newSet = new Set(prev);
        newSet.delete(carpetId);
        return newSet;
      });
    }, 1000);
    // 调用父组件的添加购物车方法
    onAddToCart(carpetId, 1);
    
    // 组件卸载时清除定时器,避免内存泄漏
    return () => clearTimeout(timer);
  };

  return (
    <>
      {products.map((carpet) => (
        <div
          className="shrink-0 cursor-pointer w-[18rem] sm:max-w-sm"
          key={carpet.id}
        >
          <div className="relative">
            <img
              src={carpet.image.url}
              alt="carpet"
              className="object-cover h-[18em] w-80 rounded-xl"
            />
            <div
              onClick={() => handleAddToCart(carpet.id)}
              className="absolute bg-white text-slate-500 hover:bg-slate-200 right-[1rem] bottom-[1rem] p-4 text-xl rounded-full"
            >
              {/* 判断当前产品是否在加载状态,显示对应内容 */}
              {loadingIds.has(carpet.id) ? (
                <svg
                  aria-hidden="true"
                  className="w-6 h-6 animate-spin text-slate-300 fill-blue-500"
                  viewBox="0 0 100 101"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
                    fill="currentColor"
                  />
                  <path
                    d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
                    fill="currentFill"
                  />
                </svg>
              ) : (
                <FiShoppingCart />
              )}
            </div>
          </div>
          <div className="flex justify-between p-2 py-4">
            <div>
              <h3 className="dark:text-white font-bold text-xl">
                {carpet.name}
              </h3>
              <p
                dangerouslySetInnerHTML={{ __html: carpet.description }}
                className="text-slate-400 text-sm"
              />
            </div>
            <div className="bg-gradient-to-r from-orange-500 to-yellow-500 flex items-center justify-center h-10 px-5 rounded-lg font-bold ">
              ${carpet.price.formatted}
            </div>
          </div>
        </div>
      ))}
    </>
  );
};

export default Carpet;

关键说明

  • 使用Set存储加载中的产品ID,天然支持去重和快速查找,比数组更高效
  • 点击时用函数式更新状态,确保操作基于最新的状态值
  • 每个产品独立判断状态,不会互相干扰
  • 添加定时器清理逻辑,避免组件卸载后定时器仍执行导致的内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:15:30