react зачем нужен key

Lists and Keys

First, let’s review how you transform lists in JavaScript.

Given the code below, we use the map() function to take an array of numbers and double their values. We assign the new array returned by map() to the variable doubled and log it:

This code logs [2, 4, 6, 8, 10] to the console.

In React, transforming arrays into lists of elements is nearly identical.

Rendering Multiple Components

We include the entire listItems array inside a

    element, and render it to the DOM:

This code displays a bullet list of numbers between 1 and 5.

Basic List Component

Usually you would render lists inside a component.

We can refactor the previous example into a component that accepts an array of numbers and outputs a list of elements.

When you run this code, you’ll be given a warning that a key should be provided for list items. A “key” is a special string attribute you need to include when creating lists of elements. We’ll discuss why it’s important in the next section.

Let’s assign a key to our list items inside numbers.map() and fix the missing key issue.

Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:

The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. Most often you would use IDs from your data as keys:

When you don’t have stable IDs for rendered items, you may use the item index as a key as a last resort:

We don’t recommend using indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state. Check out Robin Pokorny’s article for an in-depth explanation on the negative impacts of using an index as a key. If you choose not to assign an explicit key to list items then React will default to using indexes as keys.

Here is an in-depth explanation about why keys are necessary if you’re interested in learning more.

Extracting Components with Keys

Keys only make sense in the context of the surrounding array.

Example: Incorrect Key Usage

Example: Correct Key Usage

A good rule of thumb is that elements inside the map() call need keys.

Keys Must Only Be Unique Among Siblings

Keys used within arrays should be unique among their siblings. However, they don’t need to be globally unique. We can use the same keys when we produce two different arrays:

Keys serve as a hint to React but they don’t get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name:

Embedding map() in JSX

In the examples above we declared a separate listItems variable and included it in JSX:

JSX allows embedding any expression in curly braces so we could inline the map() result:

Sometimes this results in clearer code, but this style can also be abused. Like in JavaScript, it is up to you to decide whether it is worth extracting a variable for readability. Keep in mind that if the map() body is too nested, it might be a good time to extract a component.

Источник

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

Прежде всего давайте посмотрим как можно преобразовывать списки в JavaScript.

Этот код логирует [10, 20, 30, 40, 50, 60, 70, 80, 90] в консоль

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

2.9.1 Отрисовка группы компонентов

Далее мы заключаем весь массив React-элементов items внутри элемента

    и отрисовываем его в DOM:

Этот код отображает маркированный список всех пользователей.

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

Обычно в приложениях мы отрисовываем списки внутри какого-нибудь компонента.

Давайте отрефакторим предыдущий пример, выделив компонент, который принимает массив users и выводит несортированный список элементов:

Давайте присвоим ключ key к элементам нашего списка внутри numbers.map() и исправим проблему пропущенных ключей:

2.9.3 Ключи

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

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

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

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

2.9.4 Выделение компонентов с ключами

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

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

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

Вот хорошее эмпирическое правило: элементы внутри вызова map() требуют ключей.

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

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

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

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

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

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

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

Источник

Все ли вы знаете о React key?

Я время от времени провожу собеседования, и когда вопрос касается React key, чаще всего я вижу недоумевающий взгляд, намекающий “Да, там и спрашивать вроде нечего?”. Если Вам кажется React key понятным и простым, тогда давайте проведем мини собеседование (данная статья является расшифровкой видео)

Задачка разминка

Постановка задачи

Представьте, что у нас есть массив из трех пользователей. Структура пользователя максимально примитивная, всего 2 поля, это id — уникальный идентификатор и второе поле name — собственно имя пользователя.

Попробуем отрисовать этих пользователей, для этого используем следующий код:

Давайте рассмотрим, что из себя представляем компонент User.

Я написал этот компонент на классах, для лучшей наглядности жизненного цикла. И еще один момент на который хотелось бы обратить внимание это — PureComponent. Это значит, что компонент обновится, только в случае изменения свойств (props).

В итоге в браузере мы увидим примерно следующую картину:

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key

Мы видим список из трех имен, а в консоли видим три записи, а именно DID MOUNT для каждого пользователя. Пока все логично и предсказуемо.

Интрига задачи и Вопрос

А теперь перейдем собственно к интриге задачи. Допустим у первого пользователя изменилось имя, у второго пользователя как бы это странно не звучало изменилось id, а у третьего ничего не изменилось.

Внимание вопрос!
Какие новые логи вы увидите в консоли?

Даем минутку подумать, можете поставить на паузу и попробовать ответить самостоятельно.

Осторожно Ответ!

Ну что, давайте сравнивать ответы. В браузере мы видим следующую картину:

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key

На самой страничке мы видим, что Alexander изменился на Maxim, а Dmitriy и Anton, остались на первый взгляд без изменений. А в консоли мы видим следующие логи:

Напишите в комментарии, правильно ли вы ответили? И если нет, в чем была ошибка

Разбор ответа

Давайте разберемся, почему мы получили именно такие результаты

В случае пользователя Anton, key и name до перерисовки, совпадают с key и name после перерисовки, а я напоминаю что сам компонент User это PureComponent. Соответственно никаких перерисовок компонента не произошло и следственно записей в консоли не появилось.

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key

Пользователь Alexander изменил свойство name на Maxim, а при изменении props компонент перерисовывается и логично, что вызывается componentDidUpdate. Соответственно мы и увидели запись в консоли, о том что компонент обновился.

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key

И самый непонятный пользователь Dmitriy, не смотря на то что компонент User это PureComponent и мы не меняли name, с компонентом все равно что-то происходило. А именно прошлый пользователь Dmitriy уничтожился и новый клон Dmitriy создался заново. О чем свидетельствуют записи в консоли WILL UNMOUN и DID MOUNT.

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key

В этом и состоит суть React key. Если ДО обновлений, key существовал, а ПОСЛЕ обновлений key исчез, то не важно, чему был присвоен key, этот компонент в любом случае будет уничтожен. И наоборот, если ДО обновлений key не существовал, а ПОСЛЕ обновлений key появился, тогда этот компонент в любом случае будет создан с нуля. Хотя со стороны пользователя в данном примере вы не увидите никаких изменений, как был Dmitriy так он и остался, разница может быть видна только в более сложных компонентах, или при их большом количестве

Задачка посложнее

Идею я думаю вы уловили, но любую теорию нужно закрепить более сложными примерами!

Предыстория

Как вы знаете в React сообществе бытует один спор. Это стоит ли использовать index в качестве ключа. С одной стороны люди говорят, ни в коем случае и написали даже eslint правило, которое запрещает использовать index внутри key. С другой стороны ребята используют и особых проблем по этому поводу не испытывают.

Чтобы разобраться в этой проблеме, я бы для начала заглянул, что об этом говорит React документация:

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key

А как именно негативно, рассмотрим в следующем примере.

Постановка задачи

Возьмем все тех же пользователей, только теперь их будет 5 для лучшей наглядности.

Для key будем использовать вместо idindex

А компонент User остался без изменений.

В итоге в браузере мы увидим 5 пользователей и в консоли по одной записи DID MOUNT для каждого пользователя. Далее происходит следующее, второго пользователя Dmitriy удалили из списка.

Вопрос

И тут возникает вопрос, какие логи появятся в консоли после обновлений?

Ставьте на паузу и подумайте над ответом.

Осторожно Ответ!

И так результат будет следующим

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key

Первый лог и самый спорный это WILL UNMOUNT Andrey, спорный он потому что, мы удаляли Dmitriy, а удалился Andrey. Следующие 3 лога уже немного поясняют, то что произошло на самом деле. Мы видим DID UPDATE для трех пользователей.

Разбор ответа

Давайте еще раз разберемся, что именно произошло. Было 5 пользователей. И мы начинаем мыслить как пользователь, т.е. мы нажали кнопку удалить второго пользователя Dmitriy. Соответственно и ожидаем, что именно компонент второго пользователя будет удален, а остальные компоненты останутся без изменений.

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key

А теперь давайте рассмотрим, как это видит React. До обновлений было 5 компонентов, каждому из них присвоили key. После обновлений стало 4 компонента. Каждому так же присвоен key. И react, с помощью одинакового key, соотносит компонент до рендера, с компонентом после рендера.

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key

А теперь давайте посмотрим какие имена соответствуют этим ключам.

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key

И тут начинаешь понимать, почему логи были именно такими. В компоненте, котором находился Dmitriy, теперь передали просто новый props name со значением Anton. Соответственно мы и увидели лог DID UPDATE. Тоже самое произошло и со следующими двумя компонентами, поэтому мы и увидели в консоли 3 раза DID UPDATE. А key равный 5, перестал существовать, собственно поэтому мы и увидели WILL UNMOUNT Andrey, а не WILL UNMOUNT Dmitriy.

Подведем итог задаче

Если бы мы использовали id, а не index в качестве значения для key. Все было бы совсем по другому, и у нас действительно удалился бы только один компонент который содержал пользователя Dmitriy, а остальные остались бы без изменений. Именно про такие негативные последствия и предупреждали нас в React документации. И удаление элемента как вы понимаете, это не единственный случай, когда у нас могут быть лишние рендеры, так же при drag and drop, добавлении нового элемента в середину списка и даже более специфические ситуации.

Домашка

Например представьте что у пользователей появились роли, обычный пользователь и администратор:

И в зависимости от роли рисуется, если это обычный пользователь, компонент User, а если это администратор, то компонент Admin. Для key мы по прежнему используем index.

И тут снова удалили пользователя Dmitriy.

Как думаете в этом случае какие логи будут в консоли?

Ответ я не буду раскрывать, оставлю это уже для самостоятельного изучения…

Заключение

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

Источник

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

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

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

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

Мы включаем весь массив listItems внутри элемента

    и отрисовываем его в DOM:

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

Простой компонент списка

Обычно вы будете отрисовывать списки внутри компонента.

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

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

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

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

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

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

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

Также вы можете прочитать подробное объяснение того, почему ключи необходимы, если вам интересно узнать это.

Выделение компонентов с ключами

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

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

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

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

Ключи должны быть уникальными только в пределах элементов одного уровня

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

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

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

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

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

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

Источник

Keys in React. Готовим правильно

react зачем нужен key. Смотреть фото react зачем нужен key. Смотреть картинку react зачем нужен key. Картинка про react зачем нужен key. Фото react зачем нужен key
Что говорит уточка, когда узнала, что ты не используешь key

Чтобы представить работу ключей полностью и с различными кейсами, рассмотрим план:

Так как материала немало, в конце каждой части будут выводы. В конце статьи также приведен общий вывод и кратко описаны тезисы. Код можно будет смотреть как на примерах в codesandbox, так и под спойлерами.

Reconciliation

Главная задача ключей в реакте — помогать механизму reconciliation. Давайте создадим небольшой компонент, который будет рендерить список имен:

Мы не указали ни одного key. В консоли увидим сообщение:

Warning: Each child in an array or iterator should have a unique “key” prop.

Теперь усложним задачу и создадим инпут с кнопкой добавления нового имени в начало и в конец. Кроме этого, в componentDidUpdate и DidMount для Name компонента добавим логирование изменений, с указанием children:

Попробуйте добавить “Василий” в конец списка, а затем “Павел” в начало. Обратите внимание на консоль. Codesandbox позволяет также открыть исходный код, нажав на кнопки изменения отображения (сверху по центру).

Демонстрация работы подобного списка:

При добавлении элемента сверху получаем ситуацию, когда компоненты Name будут перерисованы и создан новый компонент с children === Василий :

Updated from Миша to Павел
Updated from Даниил to Миша
Updated from Марина to Даниил
Updated from Василий to Марина
Mounted with Василий

Почему так происходит? Давайте посмотрим на механизм reconciliation.

Полная сверка и приведение одного дерева к другому — дорогая задача с алгоритмической сложностью O(n³). Это значит — при больших количествах элементов реакт был бы медленным.
По этой причине механизм сверки VDOM работает с использованием следующих упрощений (правил):

1) Два элемента разных типов продьюсят разные поддеревья — значит, при смене типа элемента с

Аналогично работает и с React-компонентами:

2) Массивы элементов сравниваются поэлементно, т. е. реакт одновременно итерируется по двум массивам и сравнивает элементы попарно. Поэтому мы и получили перерисовку всех элементов в списке в примере с именами выше. Разберем на примере:

В случае же, когда добавляем элемент вверх:

Для решения проблемы в реакте используют атрибуты key. При добавлении key реакт будет сравнивать элементы не друг за другом, а будет искать по значению ключа. Пример с рендерингом имен станет более производительным:

Перепишем наш пример, добавив ключи. Обратите внимание, что теперь при добавлении элементов вверх списка происходит создание только одного компонента:

Замечу, что мы добавили id к нашим именам и управляем keys напрямую, не используя индекс элемента в массиве как key. Это обусловлено тем, что при добавлении имени в верх списка индексы поедут.

Подведем итог первой части:

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

Реиспользование ключей и нормализация

Усложним задачу. Теперь создадим список не абстрактных людей, а список людей — членов команды разработки. В компании две команды. Члена команды можно выделить по клику мышки. Попробуем решить задачу «в лоб». Попробуйте выделять людей и переключаться между командами:

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

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

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

В приведенном коде есть пара проблем:

Теперь элементы обрабатываются корректно:

Нормализация данных упрощает взаимодействие с дата-слоем приложения, упрощает структуру и уменьшает сложность. Например, сравните функцию toggle с нормализованными и ненормализованными данными.

Hint: Если бекенд или api отдает данные в ненормализованном формате, нормализовать их можно с помощью — https://github.com/paularmstrong/normalizr

Подведем итог второй части:

Нормализация данных и/или составные key позволяют добиться нужного эффекта:

Использование key при рендере одного элемента

Как мы обсуждали, реакт при отсутствии key сравнивает элементы старого и нового дерева попарно. При наличии ключей — ищет в списке children нужный элемент с заданным ключом. Случай, когда children состоит только из одного элемента, не исключение из правила.

Разберем другой пример — нотификации. Положим, что нотификация может быть только одна в конкретный период времени, отображается в течение нескольких секунд и исчезает. Такую нотификацию реализовать просто: компонент, который по componentDidMount ставит счетчик, по окончании счетчика анимирует скрытие нотификации, например:

Мы получили простой компонент.

Здесь мы получили намного больше кода, который перезапускает таймаут, если контент нотификации изменился, и убирает класс notification_hide при обновлении данных.

Таким образом

В редких случаях использование key при рендере одного компонента оправданно. key — очень мощный способ «помогать» механизму reconciliation понимать, нужно ли сравнивать компоненты или стоит сразу же (пере)создать новый.

Работа с ключами при передаче компоненту children

Кроме того, в консоли будет warning:

Warning: TestKey: key is not a prop. Trying to access it will result in undefined being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://fb.me/react-special-props)

Подытожим:

key и ref — special props в реакте. Они не включаются в объект props и недоступны внутри самого компонента.

Мы рассмотрели области применения key, как он передается в компонент, каким образом изменяется механизм reconciliation с заданием key и без него. А также посмотрели на использование key для элементов, которые являются единственным child. Сгруппируем в конце основные тезисы:

Без key механизм reconciliation сверяет компоненты попарно между текущим и новым VDOM. Из-за этого может происходить большое количество лишних перерисовок интерфейса, что замедляет работу приложения.

В редких случаях key используют и для одного элемента. Это сокращает размер кода и упрощает понимание. Но область применения этого подхода ограничена.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *