如何动态呈现图标?

How can I render an icon dynamically?

如何只动态渲染图标 cartIcon?因为现在,就像下面的代码,当我用鼠标进入组件时,所有出现的图标不仅是单个产品的图标。

我认为是因为地图,但我如何才能只渲染它?

interface IItemsProps {
  products: ProductsType;
}

const Items: React.FunctionComponent<IItemsProps> = ({ products }) => {
  const [state, setState] = React.useState<boolean>(false);

  const handleMouseEnter = () => {
    setState(true);
  };

  const handleMouseLeave = () => {
    setState(false);
  };

  const itemUI = products.map((item: SingleProductsType) => {
    const { name, price, _id } = item;

    return (
      <WrapperSingleItem key={uuidv4()} id={_id}>
        {state && <IconsCarts />} ** //HERE I NEED TO SHOW THIS COMPONENT ONLY WHEN I 
                                   // ENTER WITH THE MOUSE BUT ONLY FOR THE SELECTED 
                                    //PRODUCT NOT ALL OF THEM **
        <ImgProduct
          src={mouse}
          alt={name}
          onMouseEnter={handleMouseEnter}
          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;

在 state 中使用布尔值,您只知道是否显示图标,但是知道 哪个 列表项显示图标呢?与其将状态作为布尔值,不如我们使用产品的索引。

interface IItemsProps {
  products: ProductsType;
}

const Items: React.FunctionComponent<IItemsProps> = ({ products }) => {
  const [state, setState] = React.useState<number>(-1);

  const handleMouseEnter = (index) => {
    setState(index);
  };

  const handleMouseLeave = () => {
    setState(-1);
  };

  const itemUI = products.map((item: SingleProductsType, index: number) => {
    const { name, price, _id } = item;

    return (
      <WrapperSingleItem key={uuidv4()} id={_id}>
        {state === index && <IconsCarts />} ** //Check if index matches state before showing icon **
        <ImgProduct
          src={mouse}
          alt={name}
          onMouseEnter={() => handleMouseEnter(index)}
          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;

现在显示图标的条件是列表项的索引是否与状态中的索引匹配。然后我们将索引传递给 handleMouseEnter 以将状态设置为该索引,handleMouseLeave 会将其重置为 -1。

您可以将悬停的 _id 存储在状态中,这样您就知道它是哪一个了。

const [state, setState] = React.useState<string | null>(null); // or `number` ?

然后

{state === _id && <IconsCarts />}

<ImgProduct
  src={mouse}
  alt={name}
  onMouseEnter={() => setState(_id)}
  onMouseLeave={() => setState(null)}
/>

或者您可以将 useState 移动到一个称为地图的每个循环的组件中,以便每个项目都有自己的私有状态。

function MyItem({item}: { item: SingleProductsType }) {
    const [state, setState] = React.useState<boolean>(false);

    const { name, price, _id } = item;

    return (
      <WrapperSingleItem key={uuidv4()} id={_id}>
        {state && <IconsCarts />}

        <ImgProduct
          src={mouse}
          alt={name}
          onMouseEnter={handleMouseEnter}
          onMouseLeave={handleMouseLeave}
        />
        <WrapperTextProduct>
          <TextName>{name}</TextName>
          <div>
            <TextActualPrice>$ {price}</TextActualPrice>
            <TextPreviousPrice>
              $ {Math.trunc((price * 20) / 100 + price)}.00
            </TextPreviousPrice>
          </div>
        </WrapperTextProduct>
      </WrapperSingleItem>
    );
}

现在您可以:

{products.map((item: SingleProductsType) => <MyItem item={item} />}

最后,如果您只想 show/hide 使用鼠标输入某个元素时的购物车图标,则此解决方案可能有点矫枉过正。您可以单独使用 CSS 来完成此操作,这将是一个更简洁的解决方案,因为它不需要任何 javascript 代码,而且您根本不必跟踪状态。

.item {
  width: 100px;
  height: 100px;
  background: #aaa;
  margin: 10px;
}

.item button {
  display: none;
}

.item:hover button {
  display: block;
}
<div class="item">
  Foo
  <button>Add to cart</button>
</div>
<div class="item">
  Bar
  <button>Add to cart</button>
</div>
<div class="item">
  Baz
  <button>Add to cart</button>
</div>