[JavaScript, ReactJS] Все ли вы знаете о React key?
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Привет, Хабр!
Я время от времени провожу собеседования, и когда вопрос касается React key, чаще всего я вижу недоумевающий взгляд, намекающий “Да, там и спрашивать вроде нечего?”. Если Вам кажется React key понятным и простым, тогда давайте проведем мини собеседование (данная статья является расшифровкой видео)
Задачка разминка
Постановка задачи
Представьте, что у нас есть массив из трех пользователей. Структура пользователя максимально примитивная, всего 2 поля, это id — уникальный идентификатор и второе поле name — собственно имя пользователя.
const users = [{
id: 1,
name: 'Alexander',
}, {
id: 2,
name: 'Dmitriy',
}, {
id: 3,
name: 'Anton',
}];
Попробуем отрисовать этих пользователей, для этого используем следующий код:
const Users = ({ users }) => {
return users.map((user) => {
return (
<User
key={user.id}
name={user.name}
/>
);
}
}
Давайте рассмотрим, что из себя представляем компонент User.
class User extends PureComponent {
componentDidMount() {
console.log("DID MOUNT ", this.props.name);
}
componentDidUpdate(prevProps) {
console.log("DID UPDATE ", prevProps.name, " -> ", this.props.name);
}
componentWillUnmount() {
console.log("WILL UNMOUNT ", this.props.name);
}
render() {
return (
<span>{this.props.name}</span>
);
}
}
Я написал этот компонент на классах, для лучшей наглядности жизненного цикла. И еще один момент на который хотелось бы обратить внимание это — PureComponent. Это значит, что компонент обновится, только в случае изменения свойств (props).
В итоге в браузере мы увидим примерно следующую картину:
Мы видим список из трех имен, а в консоли видим три записи, а именно DID MOUNT для каждого пользователя. Пока все логично и предсказуемо.
Интрига задачи и Вопрос
А теперь перейдем собственно к интриге задачи. Допустим у первого пользователя изменилось имя, у второго пользователя как бы это странно не звучало изменилось id, а у третьего ничего не изменилось.
const users = [{
id: 1,
name: 'Maxim', // 'Alexander',
}, {
id: 4, // 2,
name: 'Dmitriy',
}, {
id: 3,
name: 'Anton',
}];
Внимание вопрос!
Какие новые логи вы увидите в консоли?
Даем минутку подумать, можете поставить на паузу и попробовать ответить самостоятельно...
Осторожно Ответ!
Ну что, давайте сравнивать ответы. В браузере мы видим следующую картину:
На самой страничке мы видим, что Alexander изменился на Maxim, а Dmitriy и Anton, остались на первый взгляд без изменений. А в консоли мы видим следующие логи:
- WILL UNMOUNT Dmitriy
- DID UPDATE Alexander изменился на Maxim
- Dmitriy снова вернулся в строй.
Напишите в комментарии, правильно ли вы ответили? И если нет, в чем была ошибка
Разбор ответа
Давайте разберемся, почему мы получили именно такие результаты
В случае пользователя Anton, key и name до перерисовки, совпадают с key и name после перерисовки, а я напоминаю что сам компонент User это PureComponent. Соответственно никаких перерисовок компонента не произошло и следственно записей в консоли не появилось.
Пользователь Alexander изменил свойство name на Maxim, а при изменении props компонент перерисовывается и логично, что вызывается componentDidUpdate. Соответственно мы и увидели запись в консоли, о том что компонент обновился.
И самый непонятный пользователь Dmitriy, не смотря на то что компонент User это PureComponent и мы не меняли name, с компонентом все равно что-то происходило. А именно прошлый пользователь Dmitriy уничтожился и новый клон Dmitriy создался заново. О чем свидетельствуют записи в консоли WILL UNMOUN и DID MOUNT.
В этом и состоит суть React key. Если ДО обновлений, key существовал, а ПОСЛЕ обновлений key исчез, то не важно, чему был присвоен key, этот компонент в любом случае будет уничтожен. И наоборот, если ДО обновлений key не существовал, а ПОСЛЕ обновлений key появился, тогда этот компонент в любом случае будет создан с нуля. Хотя со стороны пользователя в данном примере вы не увидите никаких изменений, как был Dmitriy так он и остался, разница может быть видна только в более сложных компонентах, или при их большом количестве
Задачка посложнее
Идею я думаю вы уловили, но любую теорию нужно закрепить более сложными примерами!
Предыстория
Как вы знаете в React сообществе бытует один спор. Это стоит ли использовать index в качестве ключа. С одной стороны люди говорят, ни в коем случае и написали даже eslint правило, которое запрещает использовать index внутри key. С другой стороны ребята используют и особых проблем по этому поводу не испытывают.
Чтобы разобраться в этой проблеме, я бы для начала заглянул, что об этом говорит React документация:
А как именно негативно, рассмотрим в следующем примере.
Постановка задачи
Возьмем все тех же пользователей, только теперь их будет 5 для лучшей наглядности.
const users = [{
id: 1,
name: 'Alexander',
}, {
id: 2,
name: 'Dmitriy',
}, {
id: 3,
name: 'Anton',
}, {
id: 4,
name: 'Artem',
}, {
id: 5,
name: 'Andrey',
}];
Для key будем использовать вместо id — index
const Users = ({ users }) => {
return users.map((user) => {
return (
<User
key={index}
name={user.name}
/>
);
}
}
А компонент User остался без изменений.
В итоге в браузере мы увидим 5 пользователей и в консоли по одной записи DID MOUNT для каждого пользователя. Далее происходит следующее, второго пользователя Dmitriy удалили из списка.
const users = [{
id: 1,
name: 'Alexander',
}/*, {
id: 2,
name: 'Dmitriy',
}*/, {
id: 3,
name: 'Anton',
}, {
id: 4,
name: 'Artem',
}, {
id: 5,
name: 'Andrey',
}];
Вопрос
И тут возникает вопрос, какие логи появятся в консоли после обновлений?
Ставьте на паузу и подумайте над ответом.
Осторожно Ответ!
И так результат будет следующим
Первый лог и самый спорный это WILL UNMOUNT Andrey, спорный он потому что, мы удаляли Dmitriy, а удалился Andrey. Следующие 3 лога уже немного поясняют, то что произошло на самом деле. Мы видим DID UPDATE для трех пользователей.
Разбор ответа
Давайте еще раз разберемся, что именно произошло. Было 5 пользователей. И мы начинаем мыслить как пользователь, т.е. мы нажали кнопку удалить второго пользователя Dmitriy. Соответственно и ожидаем, что именно компонент второго пользователя будет удален, а остальные компоненты останутся без изменений.
А теперь давайте рассмотрим, как это видит React. До обновлений было 5 компонентов, каждому из них присвоили key. После обновлений стало 4 компонента. Каждому так же присвоен 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, добавлении нового элемента в середину списка и даже более специфические ситуации.
Домашка
Например представьте что у пользователей появились роли, обычный пользователь и администратор:
const users = [{
id: 1,
name: 'Alexander',
role: 'user',
}, {
id: 2,
name: 'Dmitriy',
role: 'admin',
}, {
id: 3,
name: 'Anton',
role: 'user',
}, {
id: 4,
name: 'Artem',
role: 'admin',
}, {
id: 5,
name: 'Andrey',
role: 'user',
}];
И в зависимости от роли рисуется, если это обычный пользователь, компонент User, а если это администратор, то компонент Admin. Для key мы по прежнему используем index.
const Users = ({ users }) => {
return users.map((user) => {
const Component = user.role === 'admin' ? Admin : User;
return (
<Component
key={index}
name={user.name}
/>
);
}
}
И тут снова удалили пользователя Dmitriy.
Как думаете в этом случае какие логи будут в консоли?
Ответ я не буду раскрывать, оставлю это уже для самостоятельного изучения…
Заключение
Особенного итога в данной статье нет. Надеюсь Вам было просто интересно и любопытно выполнять мои задачки и возможно вы открыли для себя, что то новое, а если Вам настолько понравилось и Вы хотите еще, ловите ссылку
===========
Источник:
habr.com
===========
Похожие новости:
- [JavaScript] Namespaces в JavaScript
- [Разработка веб-сайтов, ReactJS] React — Используйте стандартные пропсы для потока данных
- [Информационная безопасность, JavaScript, Google Chrome, Браузеры] Google Chrome начнет блокировать JavaScript-редирект по кликам на ссылки
- [Разработка веб-сайтов, JavaScript, Программирование] 20+ ES6-сниппетов для решения практических задач (перевод)
- [Разработка веб-сайтов, Управление продуктом] Как мы создавали первый онлайн-сервис Автокредит
- [JavaScript, Программирование, Я пиарюсь, Lisp] Как я устал от JavaScript и создал свой собственный язык программирования
- [JavaScript, HTML, Node.JS] Написание графического приложения на Electron JS (начало: Создание окна)
- [Разработка веб-сайтов, JavaScript, Программирование] Пример практического использования модулей
- [Высокая производительность, Разработка веб-сайтов, JavaScript, Клиентская оптимизация, ReactJS] Производительность приложений, работающих с Video и Audio
- [Разработка веб-сайтов, JavaScript, VueJS] Автоматическое обновление скриптов после деплоя
Теги для поиска: #_javascript, #_reactjs, #_reactjs, #_react_key, #_react_key_prop, #_javascript, #_reactjs
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 15:43
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Привет, Хабр! Я время от времени провожу собеседования, и когда вопрос касается React key, чаще всего я вижу недоумевающий взгляд, намекающий “Да, там и спрашивать вроде нечего?”. Если Вам кажется React key понятным и простым, тогда давайте проведем мини собеседование (данная статья является расшифровкой видео) Задачка разминка Постановка задачи Представьте, что у нас есть массив из трех пользователей. Структура пользователя максимально примитивная, всего 2 поля, это id — уникальный идентификатор и второе поле name — собственно имя пользователя. const users = [{
id: 1, name: 'Alexander', }, { id: 2, name: 'Dmitriy', }, { id: 3, name: 'Anton', }]; Попробуем отрисовать этих пользователей, для этого используем следующий код: const Users = ({ users }) => {
return users.map((user) => { return ( <User key={user.id} name={user.name} /> ); } } Давайте рассмотрим, что из себя представляем компонент User. class User extends PureComponent {
componentDidMount() { console.log("DID MOUNT ", this.props.name); } componentDidUpdate(prevProps) { console.log("DID UPDATE ", prevProps.name, " -> ", this.props.name); } componentWillUnmount() { console.log("WILL UNMOUNT ", this.props.name); } render() { return ( <span>{this.props.name}</span> ); } } Я написал этот компонент на классах, для лучшей наглядности жизненного цикла. И еще один момент на который хотелось бы обратить внимание это — PureComponent. Это значит, что компонент обновится, только в случае изменения свойств (props). В итоге в браузере мы увидим примерно следующую картину: Мы видим список из трех имен, а в консоли видим три записи, а именно DID MOUNT для каждого пользователя. Пока все логично и предсказуемо. Интрига задачи и Вопрос А теперь перейдем собственно к интриге задачи. Допустим у первого пользователя изменилось имя, у второго пользователя как бы это странно не звучало изменилось id, а у третьего ничего не изменилось. const users = [{
id: 1, name: 'Maxim', // 'Alexander', }, { id: 4, // 2, name: 'Dmitriy', }, { id: 3, name: 'Anton', }]; Внимание вопрос! Какие новые логи вы увидите в консоли? Даем минутку подумать, можете поставить на паузу и попробовать ответить самостоятельно... Осторожно Ответ! Ну что, давайте сравнивать ответы. В браузере мы видим следующую картину: На самой страничке мы видим, что Alexander изменился на Maxim, а Dmitriy и Anton, остались на первый взгляд без изменений. А в консоли мы видим следующие логи:
Напишите в комментарии, правильно ли вы ответили? И если нет, в чем была ошибка Разбор ответа Давайте разберемся, почему мы получили именно такие результаты В случае пользователя Anton, key и name до перерисовки, совпадают с key и name после перерисовки, а я напоминаю что сам компонент User это PureComponent. Соответственно никаких перерисовок компонента не произошло и следственно записей в консоли не появилось. Пользователь Alexander изменил свойство name на Maxim, а при изменении props компонент перерисовывается и логично, что вызывается componentDidUpdate. Соответственно мы и увидели запись в консоли, о том что компонент обновился. И самый непонятный пользователь Dmitriy, не смотря на то что компонент User это PureComponent и мы не меняли name, с компонентом все равно что-то происходило. А именно прошлый пользователь Dmitriy уничтожился и новый клон Dmitriy создался заново. О чем свидетельствуют записи в консоли WILL UNMOUN и DID MOUNT. В этом и состоит суть React key. Если ДО обновлений, key существовал, а ПОСЛЕ обновлений key исчез, то не важно, чему был присвоен key, этот компонент в любом случае будет уничтожен. И наоборот, если ДО обновлений key не существовал, а ПОСЛЕ обновлений key появился, тогда этот компонент в любом случае будет создан с нуля. Хотя со стороны пользователя в данном примере вы не увидите никаких изменений, как был Dmitriy так он и остался, разница может быть видна только в более сложных компонентах, или при их большом количестве Задачка посложнее Идею я думаю вы уловили, но любую теорию нужно закрепить более сложными примерами! Предыстория Как вы знаете в React сообществе бытует один спор. Это стоит ли использовать index в качестве ключа. С одной стороны люди говорят, ни в коем случае и написали даже eslint правило, которое запрещает использовать index внутри key. С другой стороны ребята используют и особых проблем по этому поводу не испытывают. Чтобы разобраться в этой проблеме, я бы для начала заглянул, что об этом говорит React документация: А как именно негативно, рассмотрим в следующем примере. Постановка задачи Возьмем все тех же пользователей, только теперь их будет 5 для лучшей наглядности. const users = [{
id: 1, name: 'Alexander', }, { id: 2, name: 'Dmitriy', }, { id: 3, name: 'Anton', }, { id: 4, name: 'Artem', }, { id: 5, name: 'Andrey', }]; Для key будем использовать вместо id — index const Users = ({ users }) => {
return users.map((user) => { return ( <User key={index} name={user.name} /> ); } } А компонент User остался без изменений. В итоге в браузере мы увидим 5 пользователей и в консоли по одной записи DID MOUNT для каждого пользователя. Далее происходит следующее, второго пользователя Dmitriy удалили из списка. const users = [{
id: 1, name: 'Alexander', }/*, { id: 2, name: 'Dmitriy', }*/, { id: 3, name: 'Anton', }, { id: 4, name: 'Artem', }, { id: 5, name: 'Andrey', }]; Вопрос И тут возникает вопрос, какие логи появятся в консоли после обновлений? Ставьте на паузу и подумайте над ответом. Осторожно Ответ! И так результат будет следующим Первый лог и самый спорный это WILL UNMOUNT Andrey, спорный он потому что, мы удаляли Dmitriy, а удалился Andrey. Следующие 3 лога уже немного поясняют, то что произошло на самом деле. Мы видим DID UPDATE для трех пользователей. Разбор ответа Давайте еще раз разберемся, что именно произошло. Было 5 пользователей. И мы начинаем мыслить как пользователь, т.е. мы нажали кнопку удалить второго пользователя Dmitriy. Соответственно и ожидаем, что именно компонент второго пользователя будет удален, а остальные компоненты останутся без изменений. А теперь давайте рассмотрим, как это видит React. До обновлений было 5 компонентов, каждому из них присвоили key. После обновлений стало 4 компонента. Каждому так же присвоен 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, добавлении нового элемента в середину списка и даже более специфические ситуации. Домашка Например представьте что у пользователей появились роли, обычный пользователь и администратор: const users = [{
id: 1, name: 'Alexander', role: 'user', }, { id: 2, name: 'Dmitriy', role: 'admin', }, { id: 3, name: 'Anton', role: 'user', }, { id: 4, name: 'Artem', role: 'admin', }, { id: 5, name: 'Andrey', role: 'user', }]; И в зависимости от роли рисуется, если это обычный пользователь, компонент User, а если это администратор, то компонент Admin. Для key мы по прежнему используем index. const Users = ({ users }) => {
return users.map((user) => { const Component = user.role === 'admin' ? Admin : User; return ( <Component key={index} name={user.name} /> ); } } И тут снова удалили пользователя Dmitriy. Как думаете в этом случае какие логи будут в консоли? Ответ я не буду раскрывать, оставлю это уже для самостоятельного изучения… Заключение Особенного итога в данной статье нет. Надеюсь Вам было просто интересно и любопытно выполнять мои задачки и возможно вы открыли для себя, что то новое, а если Вам настолько понравилось и Вы хотите еще, ловите ссылку =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 15:43
Часовой пояс: UTC + 5