Spec-Zone.ru › React

Отображение списков

Часто вам нужно отобразить несколько похожих компонентов из коллекции данных. Вы можете использовать методы массивов JavaScript методы массивов JavaScript, чтобы манипулировать массивом данных. На этой странице вы будете использовать filter() и map() с React для фильтрации и преобразования массива данных в массив компонентов.

Вы узнаете

  • Как отображать компоненты из массива, используя методы JavaScript map()
  • Как отображать только определенные компоненты, используя методы JavaScript filter()
  • Когда и почему использовать React keys

Отображение данных из массивов

Предположим, у вас есть список элементов контента.

<ul>
  <li>Creola Katherine Johnson: mathematician</li>
  <li>Mario José Molina-Pasquel Henríquez: chemist</li>
  <li>Mohammad Abdus Salam: physicist</li>
  <li>Percy Lavon Julian: chemist</li>
  <li>Subrahmanyan Chandrasekhar: astrophysicist</li>
</ul>

Единственное различие между элементами списка — это их содержимое, их данные. При создании интерфейсов вам часто нужно отображать несколько экземпляров одного и того же компонента с различными данными: от списков комментариев до галерей профильных изображений. В таких ситуациях вы можете хранить эти данные в JavaScript-объектах и массивах и использовать методы, такие как map() и filter(), чтобы отобразить списки компонентов из них.

Вот краткий пример того, как сгенерировать список элементов из массива:

  1. Переместите данные в массив:
const people = [
  'Creola Katherine Johnson: mathematician',
  'Mario José Molina-Pasquel Henríquez: chemist',
  'Mohammad Abdus Salam: physicist',
  'Percy Lavon Julian: chemist',
  'Subrahmanyan Chandrasekhar: astrophysicist'
];
  1. Отобразите элементы people в новый массив узлов JSX, listItems:
const listItems = people.map(person => <li>{person}</li>);
  1. Возвратите listItems из вашего компонента, обернутого в <ul>:
return <ul>{listItems}</ul>;

Вот результат:

const people = [
  'Creola Katherine Johnson: mathematician',
  'Mario José Molina-Pasquel Henríquez: chemist',
  'Mohammad Abdus Salam: physicist',
  'Percy Lavon Julian: chemist',
  'Subrahmanyan Chandrasekhar: astrophysicist'
];

export default function List() {
  const listItems = people.map(person =>
    <li>{person}</li>
  );
  return <ul>{listItems}</ul>;
}

Обратите внимание, что в песочнице выше отображается ошибка консоли:

Консоль
Предупреждение: Каждый элемент в списке должен иметь уникальный атрибут «ключ».

Вы узнаете, как исправить эту ошибку позже на этой странице. Прежде чем перейти к этому, давайте добавим структуру вашим данным.

Фильтрация массивов элементов

Эти данные могут быть структурированы еще больше.

const people = [{
  id: 0,
  name: 'Creola Katherine Johnson',
  profession: 'mathematician',
}, {
  id: 1,
  name: 'Mario José Molina-Pasquel Henríquez',
  profession: 'chemist',
}, {
  id: 2,
  name: 'Mohammad Abdus Salam',
  profession: 'physicist',
}, {
  id: 3,
  name: 'Percy Lavon Julian',
  profession: 'chemist',  
}, {
  id: 4,
  name: 'Subrahmanyan Chandrasekhar',
  profession: 'astrophysicist',
}];

Допустим, вы хотите отобразить только людей, чья профессия 'chemist'. Вы можете использовать метод JavaScript filter() для возврата только этих людей. Этот метод принимает массив элементов, пропускает их через «тест» (функцию, которая возвращает true или false), и возвращает новый массив только тех элементов, которые прошли тест (вернули true).

Вам нужны только те элементы, где profession — 'chemist'. Функция «теста» для этого выглядит так: (person) => person.profession === 'chemist'. Вот как это собрать:

  1. Создайте новый массив только «химиков», chemists, вызвав filter() для массива people, отфильтровав по person.profession === 'chemist':
const chemists = people.filter(person =>
  person.profession === 'chemist'
);
  1. Теперь отобразите элементы chemists:
const listItems = chemists.map(person =>
  <li>
     <img
       src={getImageUrl(person)}
       alt={person.name}
     />
     <p>
       <b>{person.name}:</b>
       {' ' + person.profession + ' '}
       known for {person.accomplishment}
     </p>
  </li>
);
  1. Наконец, верните listItems из вашего компонента:
return <ul>{listItems}</ul>;
import { people } from './data.js';
import { getImageUrl } from './utils.js';

export default function List() {
  const chemists = people.filter(person =>
    person.profession === 'chemist'
  );
  const listItems = chemists.map(person =>
    <li>
      <img
        src={getImageUrl(person)}
        alt={person.name}
      />
      <p>
        <b>{person.name}:</b>
        {' ' + person.profession + ' '}
        known for {person.accomplishment}
      </p>
    </li>
  );
  return <ul>{listItems}</ul>;
}

Опасность

Стрелочные функции неявно возвращают выражение сразу после =>, поэтому вам не нужен оператор return:

const listItems = chemists.map(person =>
  <li>...</li> // Implicit return!
);

Однако, вы должны явно написать return если ваша стрелочная функция => содержит оператор { фигурных скобок!

const listItems = chemists.map(person => { // Curly brace
  return <li>...</li>;
});

Стрелочные функции с => { называются функциями с «блочным телом». Они позволяют вам писать более одной строки кода, но вы обязаны сами писать оператор return. Если вы его забудете, ничего не вернётся!

Поддержание порядка элементов списка с key

Обратите внимание, что во всех песочницах выше отображается ошибка в консоли:

Консоль
Предупреждение: Каждый элемент в списке должен иметь уникальный атрибут «ключ».

Вы должны присвоить каждому элементу массива key — строку или число, уникально идентифицирующее его среди других элементов в этом массиве:

<li key={person.id}>...</li>

Примечание

Элементы JSX, непосредственно внутри вызова map() всегда требуют ключей!

Ключи говорят React, какому элементу массива соответствует каждый компонент, чтобы он мог сопоставить их позже. Это становится важным, если элементы вашего массива могут перемещаться (например, из-за сортировки), вставляться или удаляться. Хорошо выбранный key помогает React определить, что именно произошло, и выполнить правильные обновления дерева DOM.

Вместо генерации ключей на лету, вы должны включать их в свои данные:

export const people = [{
  id: 0, // Used in JSX as a key
  name: 'Creola Katherine Johnson',
  profession: 'mathematician',
  accomplishment: 'spaceflight calculations',
  imageId: 'MK3eW3A'
}, {
  id: 1, // Used in JSX as a key
  name: 'Mario José Molina-Pasquel Henríquez',
  profession: 'chemist',
  accomplishment: 'discovery of Arctic ozone hole',
  imageId: 'mynHUSa'
}, {
  id: 2, // Used in JSX as a key
  name: 'Mohammad Abdus Salam',
  profession: 'physicist',
  accomplishment: 'electromagnetism theory',
  imageId: 'bE7W1ji'
}, {
  id: 3, // Used in JSX as a key
  name: 'Percy Lavon Julian',
  profession: 'chemist',
  accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
  imageId: 'IOjWm71'
}, {
  id: 4, // Used in JSX as a key
  name: 'Subrahmanyan Chandrasekhar',
  profession: 'astrophysicist',
  accomplishment: 'white dwarf star mass calculations',
  imageId: 'lrWQx8l'
}];

Подробное изучение

Отображение нескольких узлов DOM для каждого элемента списка

Что делать, если каждому элементу нужно отображать не один, а несколько узлов DOM?

Короткий синтаксис <>...</> фрагмента не позволит вам передать ключ, поэтому вам нужно либо сгруппировать их в один <div>, либо использовать чуть более длинный и более явный <Fragment> синтаксис:

import { Fragment } from 'react';

// ...

const listItems = people.map(person =>
  <Fragment key={person.id}>
    <h1>{person.name}</h1>
    <p>{person.bio}</p>
  </Fragment>
);

Фрагменты исчезают из DOM, поэтому это приведет к плоскому списку <h1>, <p>, <h1>, <p>, и так далее.

Где получить свой key

Различные источники данных предоставляют различные источники ключей:

  • Данные из базы данных: если ваши данные поступают из базы данных, вы можете использовать ключи/ID базы данных, которые по своей природе уникальны.
  • Данные, сгенерированные локально: если ваши данные генерируются и сохраняются локально (например, заметки в приложении для заметок), используйте инкрементный счётчик, crypto.randomUUID() или пакет, такой как uuid при создании элементов.

Правила ключей

  • Ключи должны быть уникальными среди своих братьев и сестер. Тем не менее, использование одних и тех же ключей для узлов JSX в различных массивах допустимо.
  • Ключи не должны меняться, иначе это лишает их смысла! Не генерируйте их во время рендеринга.

Почему React нуждается в ключах?

Представьте, что файлы на вашем рабочем столе не имеют имён. Вместо этого вы бы ссылались на них по порядку — первый файл, второй файл и так далее. Вы могли бы к этому привыкнуть, но как только вы удалите файл, это станет запутанным. Второй файл станет первым, третий — вторым и так далее.

Имена файлов в папке и ключи JSX в массиве служат аналогичной цели. Они позволяют нам уникально идентифицировать элемент среди своих братьев и сестёр. Хорошо выбранный ключ даёт больше информации, чем положение в массиве. Даже если положение изменится из-за переупорядочивания, key позволяет React идентифицировать элемент на протяжении всего его жизненного цикла.

Опасность

Вы можете быть искушены использовать индекс элемента в массиве в качестве его ключа. На самом деле, React использует это, если вы не задаёте key вообще. Но порядок отображения элементов будет меняться со временем, если элемент вставляется, удаляется или если массив переупорядочивается. Индекс в качестве ключа часто приводит к скрытым и запутанным ошибкам.

Аналогично, не генерируйте ключи на лету, например, с key={Math.random()}. Это приведёт к тому, что ключи никогда не будут совпадать между рендерингами, что приведёт к пересозданию всех ваших компонентов и DOM каждый раз. Это не только медленно, но также потеряет любой пользовательский ввод внутри элементов списка. Вместо этого используйте стабильный ID, основанный на данных.

Обратите внимание, что ваши компоненты не получат key в качестве свойства. Он используется только как подсказка для самого React. Если ваш компонент нуждается в идентификаторе, вы должны передать его как отдельное свойство: <Profile key={id} userId={id} />.

Заключение

На этой странице вы узнали:

  • Как перемещать данные из компонентов в структуры данных, такие как массивы и объекты.
  • Как генерировать наборы похожих компонентов с помощью методов JavaScript map().
  • Как создавать массивы отфильтрованных элементов с помощью методов JavaScript filter().
  • Зачем и как задавать key каждому компоненту в коллекции, чтобы React мог отслеживать каждый из них, даже если их позиция или данные меняются.

Попробуйте некоторые задачи

Задача 1 из 4:
Разделение списка на две части

В этом примере показан список всех людей.

Измените его так, чтобы отображать два отдельных списка один за другим: Химики и Остальные. Как и раньше, вы можете определить, является ли человек химиком, проверив, person.profession === 'chemist'.

import { people } from './data.js';
import { getImageUrl } from './utils.js';

export default function List() {
  const listItems = people.map(person =>
    <li key={person.id}>
      <img
        src={getImageUrl(person)}
        alt={person.name}
      />
      <p>
        <b>{person.name}:</b>
        {' ' + person.profession + ' '}
        known for {person.accomplishment}
      </p>
    </li>
  );
  return (
    <article>
      <h1>Scientists</h1>
      <ul>{listItems}</ul>
    </article>
  );
}

© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://react.dev/learn/rendering-lists

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API