如何映射组件并确保组件单独具有相同的属性

How to map components and ensure the component has the same attribute individually

目前我有一个渲染一系列图像的地图功能,我意识到它们共享相同的 hover 状态,这意味着它们在悬停时将执行相同的操作。在为它们分配 unique/individual 属性时是否有映射重复组件的标准做法?

      {itemData.map((item) => (
        <ImageListItem key={item.img}>
          <img
            src={item.img}
            alt={item.title}
            loading="lazy"
            onMouseOver={() => {setHover(true)}}
            onMouseOut={() => {setHover(false)}}
            style={{ transform: hover ? 'scale(1.5, 1.5)' : null }}
          />
          <ImageListItemBar
            title={item.title}
            subtitle={item.author}
            actionIcon={
              <IconButton
                sx={{ color: 'rgba(255, 255, 255, 0.54)' }}
                aria-label={`info about ${item.title}`}
              >
                <InfoIcon />
              </IconButton>
            }
          />

要提供独特的属性,您需要有一些东西可以唯一标识您的图像组件并使用它来管理您的状态。在您的情况下,您的状态 hover 应该是 arrayobject,而不是 boolean。由于您使用 item.img 作为密钥,我认为它是唯一的,因此它可以帮助您进行状态管理,如下所示:

const [hover, setHover] = useState({});
{itemData.map((item) => (
        <ImageListItem key={item.img}>
          <img
            src={item.img}
            alt={item.title}
            loading="lazy"
            onMouseOver={() => setHover({...hover, [item.img]: true})}
            onMouseOut={() => setHover({...hover, [item.img]: false})}
            style={{ transform: hover ? 'scale(1.5, 1.5)' : null }}
          />
          <ImageListItemBar
            title={item.title}
            subtitle={item.author}
            actionIcon={
              <IconButton
                sx={{ color: 'rgba(255, 255, 255, 0.54)' }}
                aria-label={`info about ${item.title}`}
              >
                <InfoIcon />
              </IconButton>
            }
          />
))
}

你应该使用一个组件,它为每个元素创建一个独特的状态,我写了一个易于理解的例子。

import React, { useState } from "react"

const items = [
  {
    title: 'Card1',
    price: 100
  },
  {
    title: 'Card2',
    price: 50
  },
  {
    title: 'Card3',
    price: 200
  },
]

export default function App() {
  return (
    <>
      {
        items.map(element => {
          return(
            <Card {...element}/>
          )
        })
      }
    </>
  )
}

function Card({title, price, key}) {
  const [isHovered, setHover] = useState(false) 
  
  return (
    <>
    <div
    key={key}
    onMouseOver={() => {setHover(true)}}
    onMouseOut={() => {setHover(false)}}
    >
      <div>
        {title}
      </div>
      <h3>
        {
          isHovered && price
        }
      </h3>
    </div>
    </>
  );
}

我将卡片价格设置为在悬停时显示,以便您可以看到它适用于每个单独的组件。

Code sandbox if you want to check it out.

如果您希望状态位于父级 中而不是 一直到数组或对象,您可以使用数字代替。如果一次只有一个项目处于活动状态,则可以只使用活动项目的索引作为状态:

const { useState } = React;
const things = ["foo", "bar", "baz"];

function Component() {
  const [active, setActive] = useState(-1);
  const updateActivity = (index) => setActive(index === active ? -1 : index);
  return (
    <ul>
      {things.map((thing, index) => (
        <li>
          <button key={index} onClick={() => updateActivity(index)}>
            {index === active
              ? <strong>{thing}</strong>
              : thing}
          </button>
        </li>
      ))}
      <li>Value: {active}</li>
    </ul>
  );
}

ReactDOM.render(
  <Component />,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="react"></div>

或者,如果您希望 多个 项目同时处于活动状态,您可以使用“位标志”方法,其中值的每一位代表是否对应索引处于活动状态:

const { useState } = React;
const things = ["foo", "bar", "baz"];

function Component() {
  const [active, setActive] = useState(0);
  const updateActivity = (index) => setActive(active ^ Math.pow(2, index));
  return (
    <ul>
      {things.map((thing, index) => (
        <li>
          <button key={index} onClick={() => updateActivity(index)}>
            {active & Math.pow(2, index)
              ? <strong>{thing}</strong>
              : thing}
          </button>
        </li>
      ))}
      <li>Value: {active} ({active.toString(2).padStart(3, "0")})</li>
    </ul>
  );
}

ReactDOM.render(
  <Component />,
  document.getElementById("react2")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="react2"></div>