Spec-Zone.ru › React 17

Списки и ключи

Сначала давайте рассмотрим, как преобразовать списки в JavaScript.

В приведенном ниже коде мы используем функцию map(), чтобы взять массив numbers и удвоить их значения. Мы присваиваем новый массив, возвращённый map(), переменной doubled и выводим его:

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);

Этот код выводит [2, 4, 6, 8, 10] в консоль.

В React преобразование массивов в списки элементов практически идентично.

Отображение нескольких компонентов

Вы можете создавать коллекции элементов и включать их в JSX с помощью фигурных скобок {}.

Ниже мы проходим по массиву numbers с помощью функции JavaScript map(). Мы возвращаем элемент <li> для каждого элемента. Наконец, мы присваиваем полученный массив элементов переменной listItems:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li>{number}</li>
);

Мы включаем весь массив listItems в элемент <ul> и отображаем его в DOM:

ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

Попробуйте на CodePen

Этот код отображает маркированный список чисел от 1 до 5.

Базовый компонент списка

Обычно списки отображаются внутри компонента.

Мы можем переписать предыдущий пример в компонент, принимающий массив numbers и выводящий список элементов.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

При выполнении этого кода вы получите предупреждение о том, что для элементов списка необходимо указать ключ. «Ключ» — это специальное строковое атрибут, которое необходимо включать при создании списков элементов. Мы обсудим, почему это важно, в следующем разделе.

Давайте назначим key нашим элементам списка внутри numbers.map() и исправим проблему отсутствия ключа.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Попробуйте на CodePen

Ключи

Ключи помогают React определить, какие элементы изменились, были добавлены или удалены. Элементам внутри массива следует назначать ключи, чтобы придать им устойчивую идентичность:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li key={number.toString()}>
    {number}
  </li>
);

Лучший способ выбрать ключ — использовать строку, которая однозначно идентифицирует элемент списка среди его соседей. Чаще всего в качестве ключей используются идентификаторы из ваших данных:

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

Если у отображаемых элементов нет стабильных идентификаторов, в качестве крайнего средства можно использовать индекс элемента в качестве ключа:

const todoItems = todos.map((todo, index) =>
  // Only do this if items have no stable IDs
  <li key={index}>
    {todo.text}
  </li>
);

Мы не рекомендуем использовать индексы в качестве ключей, если порядок элементов может измениться. Это может негативно сказаться на производительности и вызвать проблемы с состоянием компонентов. Ознакомьтесь со статьей Робина Покорни для подробного объяснения отрицательного влияния использования индекса в качестве ключа здесь. Если вы решите не назначать явных ключей элементам списка, React по умолчанию будет использовать индексы в качестве ключей.

Здесь вы найдёте подробное объяснение, почему ключи необходимы, если хотите узнать больше.

Извлечение компонентов с ключами

Ключи имеют смысл только в контексте окружающего массива.

Например, если вы извлекаете компонент ListItem, вы должны сохранить ключ для элементов <ListItem /> в массиве, а не для элемента <li> в самом компоненте ListItem.

Пример: Неправильное использование ключей

function ListItem(props) {
  const value = props.value;
  return (
    // Wrong! There is no need to specify the key here:
    <li key={value.toString()}>
      {value}
    </li>
  );
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Wrong! The key should have been specified here:
    <ListItem value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Пример: Правильное использование ключей

function ListItem(props) {
  // Correct! There is no need to specify the key here:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Correct! Key should be specified inside the array.
    <ListItem key={number.toString()} value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Попробуйте на CodePen

Хорошее правило — элементы внутри вызова map() нуждаются в ключах.

Ключи должны быть уникальными только среди своих соседей

Ключи, используемые внутри массивов, должны быть уникальными среди своих соседей. Однако они не должны быть глобально уникальными. Мы можем использовать те же ключи, когда генерируем два разных массива:

function Blog(props) {
  const sidebar = (
    <ul>
      {props.posts.map((post) =>
        <li key={post.id}>
          {post.title}
        </li>
      )}
    </ul>
  );
  const content = props.posts.map((post) =>
    <div key={post.id}>
      <h3>{post.title}</h3>
      <p>{post.content}</p>
    </div>
  );
  return (
    <div>
      {sidebar}
      <hr />
      {content}
    </div>
  );
}

const posts = [
  {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
  {id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
  <Blog posts={posts} />,
  document.getElementById('root')
);

Попробуйте на CodePen

Ключи служат подсказкой для React, но не передаются вашим компонентам. Если вам нужна та же самая величина в компоненте, передайте её явно как свойство с другим именем:

const content = posts.map((post) =>
  <Post
    key={post.id}    id={post.id}    title={post.title} />
);

В приведённом выше примере компонент Post может читать props.id, но не props.key.

Встраивание map() в JSX

В предыдущих примерах мы объявляли отдельную переменную listItems и включали её в JSX:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <ListItem key={number.toString()}              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

JSX позволяет встраивать любые выражения в фигурные скобки, поэтому мы можем встроить результат map():

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}                  value={number} />
      )}
    </ul>
  );
}

Попробуйте на CodePen

Иногда это приводит к более ясному коду, но этот стиль также может быть избыточным. Как и в JavaScript, вам решать, стоит ли выделять переменную для улучшения читаемости. Имейте в виду, что если тело map() слишком вложенное, это может быть хорошим моментом для извлечения компонента.

Полезная ли эта страница?

© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://17.reactjs.org/docs/lists-and-keys.html

Spec-Zone.ru

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