Выбор изображений и отображение заголовков в React

#javascript #reactjs #typescript

#javascript #reactjs #typescript

Вопрос:

У меня есть функциональный компонент React, в котором есть список изображений с заголовками:

 export function MyComponent() {
  const images = [
    { image: "http://www.example1.com/image1.jpg", title: "Title 1"},
    { image: "http://www.example2.com/image2.jpg", title: "Title 2"},
    { image: "http://www.example3.com/image3.jpg", title: "Title 3"}
  ]

  const [titles, setTitles] = React.useState([]);

  return (
    <div>

      <div>{titles}</div>

      <section className="images">{
        images.map(image => (
          <img
            src={image.image}
            alt={image.title}
            onClick={() => {}} // selects or unselects the image?
          />
          )
        )}</section>
    </div>
  );
}
  

Когда я нажимаю на изображение, я хочу, чтобы оно было либо выделено, либо не выделено. Когда он выбран, я хочу, чтобы появилась граница CSS. Если выбрано изображение, я хочу, чтобы список выбранных заголовков изображений отображался в <div>{titles}</div> . Я думал использовать React.useState() здесь, но я не уверен, как это сделать. Я не хочу проводить рефакторинг для использования класса; это должен быть функциональный компонент. Спасибо.

Ответ №1:

Я предполагаю, что вы хотите выбирать по одному изображению за раз и отображать его заголовок. Итак, вот наивный подход, который вы можете адаптировать в соответствии с вашей ситуацией.

 const images = [
  { image: "https://via.placeholder.com/150", title: "Title 1" },
  { image: "https://via.placeholder.com/150", title: "Title 2" },
  { image: "https://via.placeholder.com/150", title: "Title 3" },
];

function Main() {
  const [selected, setSelected] = React.useState();

  return (
    <div>
      <div>{images[selected] amp;amp; images[selected].title}</div>

      <section className="images">
        {images.map((image, index) => (
          <img
            className={index === selected ? "selected" : ""}
            key={`${index}${image.title}`}
            src={image.image}
            alt={image.title}
            onClick={() => setSelected(index)}
          />
        ))}
      </section>
    </div>
  );
}

ReactDOM.render(<Main />, document.getElementById("root"));  
 .selected {
  border: 5px solid black;
}  
 <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root" />  

Итак, у вас есть одно состояние, выбранное index . Для className части, которую вы ищете для изображения index , сравните с selected состоянием, затем назначьте имя класса в соответствии с этим. Для части заголовка вы просто захватываете, title используя выделенный index с условным JSX.

Но использование индексов ненадежно. Было бы лучше иметь несколько уникальных идентификаторов для изображений.

Ответ №2:

 export function MyComponent() {
  const images = [
    {
      image: 'http://www.example1.com/image1.jpg',
      title: 'Title 1',
    },
    {
      image: 'http://www.example2.com/image2.jpg',
      title: 'Title 2',
    },
    {
      image: 'http://www.example3.com/image3.jpg',
      title: 'Title 3',
    },
  ];

  const [titles, setTitles] = React.useState([]);

  return (
    <div>
      <div>{titles}</div>

      <section className="images">
        {images.map((image) => (
          <img
            style={{
              border: titles.includes(image.title) ? '3px solid black' : 'none',
            }}
            src={image.image}
            alt={image.title}
            onClick={() => {
              if (titles.includes(image.title)) {
                setTitles(titles.filter((title) => title !== image.title));
              } else setTitles([...titles, image.title]);
            }}
          />
        ))}
      </section>
    </div>
  );
}