Я создавал небольшое приложение React для отображения фильтруемого списка фильмов. В моем макете был компонент боковой панели со списком заголовков для поиска «Фильмы», «Мой список» и «Телешоу». При щелчке по каждому заголовку будет отображаться раскрывающееся меню со списком названий жанров или подфильтров.

Я столкнулся с проблемой, из-за которой щелчок по одному заголовку поиска приводил к тому, что все они теряли trow. Очевидно, это было не то, чего я хотел. В прошлых проектах мое решение этой проблемы всегда было наименее СУХИМ — дать каждому элементу списка отдельный обработчик кликов с именами вроде handleMovieClick, handleMyListClick и handleTVShowClick. Это было неправильно. Мне нужно было лучшее рабочее решение.

Как я могу дать каждому заголовку поиска уникальный идентификатор или тег, что позволило бы использовать один основной обработчик кликов? Также должен был быть способ сделать это динамичным. Это означает, что если я решу добавить больше элементов списка, решение все равно будет работать.

Итак, мы инициализируем состояние пустым массивом с именем clicked. Получив список заголовков поиска для отображения, сопоставьте их и сгенерируйте JSX для присоединения обработчика событий (того же самого обработчика событий), привязанного к индексу элемента списка. Это гарантирует, что добавление новых элементов в список будет иметь уникальный идентификатор. Создайте еще один div, содержащий информацию, которая будет отображаться при нажатии на элемент. Снова присвойте ему уникальное имя класса, используя номер индекса. Когда этот элемент щелкнут, он запустит обратный вызов для отображения своих подфильтров.

state = { clicked: [] }
handleClick = (index, e) => {
  let clicked = this.state.clicked
  clicked[index] = !clicked[index]
  this.setState({ clicked });
 }
const searchTitles = ['Movies', 'My List', 'TV Shows']
searchTitles.map((title, index) => {
  <div className='title-item' onClick={this.handleClick.bind(this, index)}>{title}}</div>
  <div className={'title-item'+' '+this.state.clicked[index]}>
    {this.state.clicked[index] && this.renderSubFilters()}
  </div>
})

Что дает нам:

<div className='title-item' onClick={this.handleClick.bind(this, 0)}>Movies}</div>
<div className={'title'+' '+this.state.clicked[0]}>
    {this.state.clicked[0] && this.renderSubFilters()}
  </div>
<div className='title-item' onClick={this.handleClick.bind(this, 1)}>My List}</div>
<div className={'title'+' '+this.state.clicked[1]}>
    {this.state.clicked[1] && this.renderSubFilters()}
  </div>
<div className='title-item' onClick={this.handleClick.bind(this, 2)}>TV Shows}</div>
<div className={'title'+' '+this.state.clicked[2]}>
    {this.state.clicked[2] && this.renderSubFilters()}
  </div>

Метод handleClick() — один из тех хитрых, но элегантно написанных кусков кода, которые заставляют вас чесать затылок, говорить сами с собой, когда вы пытаетесь выполнить именно то, что происходит. Я нашел его на StackOverflow в кроличьей норе исследований поздно ночью. Спасибо, Абхи Павитран!

Он устанавливает для переменной clicked значение this.state.clicked. Это помогает представить:

state = { clicked: [false, false, false] }

Затем он говорит: «Установите значение clicked[index] равным его противоположности». Если бы мы нажали на второй элемент, clicked стал бы таким:

state = { clicked: [false, true, false] }

Удивительный.