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

React中如何动态渲染单个商品hover触发的cartIcon,而非全部商品图标

问题根因

你当前在整个商品列表组件里共用了一个布尔类型的状态控制购物车图标显示,只要状态为真,所有遍历渲染的商品都会显示图标,和map遍历本身无关,是状态的粒度太粗导致的。

解决方案1:父组件存储当前悬浮的商品ID

修改状态存储当前hover的商品_id,而非全局布尔值,判断当前遍历到的商品ID是否等于状态中存储的ID,来决定是否显示图标:

interface IItemsProps {
  products: ProductsType;
}

const Items: React.FunctionComponent<IItemsProps> = ({ products }) => {
  // 存储当前hover的商品ID,初始为null
  const [hoveredProductId, setHoveredProductId] = React.useState<string | null>(null);

  const handleMouseEnter = (id: string) => {
    setHoveredProductId(id);
  };

  const handleMouseLeave = () => {
    setHoveredProductId(null);
  };

  const itemUI = products.map((item: SingleProductsType) => {
    const { name, price, _id } = item;
    // 不要用uuidv4当key,每次渲染都会生成新值导致组件不必要重绘,直接用商品本身的_id即可
    return (
      <WrapperSingleItem key={_id} id={_id}>
        {/* 仅当前商品ID和悬浮ID匹配时显示图标 */}
        {hoveredProductId === _id && <IconsCarts />}
        <ImgProduct
          src={mouse}
          alt={name}
          onMouseEnter={() => handleMouseEnter(_id)}
          onMouseLeave={handleMouseLeave}
        />
        <WrapperTextProduct>
          <TextName>{name}</TextName>
          <div>
            <TextActualPrice>$ {price}</TextActualPrice>
            <TextPreviousPrice>
              $ {Math.trunc((price * 20) / 100 + price)}.00
            </TextPreviousPrice>
          </div>
        </WrapperTextProduct>
      </WrapperSingleItem>
    );
  });

  return <WrapperItems>{itemUI}</WrapperItems>;
};

export default Items;

解决方案2:拆分单个商品为独立组件

把单个商品的逻辑抽成独立组件,每个组件自己维护hover状态,逻辑更内聚,互相不会干扰:

// 抽离的单个商品组件
interface ISingleItemProps {
  item: SingleProductsType;
}
const SingleItem: React.FunctionComponent<ISingleItemProps> = ({ item }) => {
  const [isHovered, setIsHovered] = React.useState<boolean>(false);
  const { name, price, _id } = item;
  
  return (
    <WrapperSingleItem id={_id}>
      {isHovered && <IconsCarts />}
      <ImgProduct
        src={mouse}
        alt={name}
        onMouseEnter={() => setIsHovered(true)}
        onMouseLeave={() => setIsHovered(false)}
      />
      <WrapperTextProduct>
        <TextName>{name}</TextName>
        <div>
          <TextActualPrice>$ {price}</TextActualPrice>
          <TextPreviousPrice>
            $ {Math.trunc((price * 20) / 100 + price)}.00
          </TextPreviousPrice>
        </div>
      </WrapperTextProduct>
    </WrapperSingleItem>
  )
}

// 原列表组件简化为只负责遍历
interface IItemsProps {
  products: ProductsType;
}
const Items: React.FunctionComponent<IItemsProps> = ({ products }) => {
  return (
    <WrapperItems>
      {products.map(item => <SingleItem key={item._id} item={item} />)}
    </WrapperItems>
  )
};

export default Items;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 19:24:06