Як працює key у React: аналіз і нестандартні кейси

💡 Усі статті, обговорення, новини про Front-end — в одному місці. Приєднуйтесь до Front-end спільноти!

Усім привіт! Мене звати Павло, я Front-end Developer у HOLYWATER — продуктовій компанії з екосистеми Genesis. Останні два роки я працюю з React та у вільний час досліджую його можливості.

Мене зацікавив атрибут key, знання про який часто обмежуються кількома тезами: його застосовують у динамічних списках, а як значення не можна використовувати index. Водночас коли натрапляєш на key={`index-${index}`}, стає зрозуміло, що навіть базові тези не всі розуміють правильно.

Це надихнуло мене заглибитися в цю концепцію React та виявити, що key має значно ширші способи використання. У цій статті хочу розібратися, як атрибут key працює під капотом у динамічних списках, а також показати інші його можливості, які допомагають контролювати поведінку React у деяких ситуаціях.

Спершу ми розглянемо, що відбувається на шляху від JSX до реального DOM, зокрема на етапі узгодження (reconciliation). Далі розберемо два окремі механізми використання key: у динамічних списках і за їхніми межами. Наостанок проаналізуємо декілька практичних прикладів, щоб краще зрозуміти потенціал key.

Ця стаття буде цікавою Junior та Middle-розробникам — діліться фідбеком та досвідом у коментарях.

JSX і Virtual DOM: як React обробляє елементи

Як відомо, JSX — це HTML-подібний синтаксис, який React надає нам для зручності (це не більше ніж синтаксичний цукор). Кожен компонент у JSX — чи то базовий (div, h1, p тощо), чи то створений нами кастомний — насправді передбачає виклик функції createElement(). Саме тому такий фрагмент коду:

<div className="element">
  Hello, world!
</div>

Можна цілком законно замінити на такий:

{React.createElement("div", { className: "element" }, "Hello, world!")}

Ця функція приймає:

  • тип елемента («div»);
  • обʼєкт props ({ className: «element» });
  • контент, який передається як children («Hello, world!»).

Результатом виклику createElement() буде обʼєкт такого типу:

{
  '$$typeof': Symbol(react.element),
  type: 'div',
  key: null,
  props: { className: 'element', children: 'Hello, world!' },
  ref: null,
  _owner: FiberNode {}
  _store: {}
}

Якщо замість простого елемента div використати компонент, то обʼєкт, що повертається, матиме такий самий вигляд, але значенням type буде наш компонент.

{
  '$$typeof': Symbol(react.element),
  type: [Function: MyComponent],
  key: null,
  props: { children: 'Hello, world!' },
  ref: null,
  _owner: FiberNode {}
  _store: {}
}

Детальний розбір цього обʼєкта — це велика і цікава тема, варта окремої статті. Нас передусім цікавлять властивості type, key та props, але додам декілька слів про інші властивості цього обʼєкта:

  • ’$$typeof’: Symbol(react.element) дозволяє React визначати, що цей обʼєкт є валідним React-елементом;
  • ref використовують для посилань на DOM-елементи;
  • _owner містить інформацію про компонент, який створив цей елемент;
  • _store використовують для перевірки пропсів.

Дисклеймер

Вищенаведені приклади обʼєктів не є вичерпними. Є інші варіанти, що можуть охоплювати мемоїзовані компоненти, React Fragment тощо, розгляд яких виходить за межі цієї статті. Також як значення в подальших прикладах для наочності я буду наводити тільки основні властивості, але зазначу, що всі перелічені вище властивості присутні в кожному обʼєкті, який створює функція createElement().

Розглянемо ще декілька прикладів.

Елемент з одним дочірнім елементом такого типу:

<div className="container">
  <div>Children 1</div>
</div>

Буде записаний в обʼєкт таким чином:

{
  type: "div",
  key: null,
  props: {
    className: "container",
    children: { 
      type: "div", 
      key: null,
      props: { children: "Children 1" },
      ... 
    }
  },
  ...
}

Дочірні елементи зберігаються в об’єкті React-елемента як значення властивості children. Це звично під час використання власних компонентів, які отримують props children, але для простих елементів на кшталт div це працює так само.

Таким чином React перетворює весь застосунок на складну ієрархію вкладених та чітко організованих об’єктів, кожен із яких відповідає конкретному вузлу в реальному DOM. Кінцева мета React — створити структуру базових елементів. Якщо він зустрічає елемент, типом якого є компонент (функція), то робить виклик цієї функції. Цей процес буде продовжуватися, доки структура обʼєктів не міститиме лише прості елементи на кшталт div, p, span тощо.

Ба більше, React зберігає цю структуру у двох версіях — поточній (щойно створеній) та попередній. Процес, відомий як reconciliation, передбачає порівняння (diffing) двох екземплярів, щоби визначити, які зміни мають бути виконані в реальному DOM. Сама структура об’єктів називається Virtual DOM.

Повернемося до прикладів і розглянемо, як виглядатиме у Virtual DOM елемент з декількома сусідніми дочірніми елементами:

<div className="container">
  <div>Children 1</div>
  <div>Children 2</div>
</div>

У такому разі обʼєкт елемента матиме такий вигляд (приклад спрощено для наочності):

{
  type: "div",
  key: null,
  props: {
    className: "container",
    children: [
      { type: "div", key: null, props: ... },
      { type: "div", key: null, props: ... }
    ]
  },
  ...
}

Тобто сусідні дочірні елементи зберігаються у властивості children у вигляді масиву.

Думаю, більшість Front-end розробників після того, як побачать останній приклад, захочуть записати його з використанням ітерації:

const items = ['Children 1', 'Children 2'];

<div className="container">
  {items.map(item => (
    <div key={item}>{item}</div>
  ))}
</div>

В результаті обʼєкт елемента має схожу структуру, проте атрибут key матиме одне з двох значень замість null.

{
  type: "div",
  key: null,
  props: {
    className: "container",
    children: [
      { type: "div", key: 'Children 1', props: ... },
      { type: "div", key: 'Children 2', props: ... }
    ]
  },
  ...
}

Але чи дійсно обʼєкт елемента буде однаковим? Це можна перевірити, розглянувши такий дещо незвичний приклад. Два елементи додамо, використовуючи map(), а третій як окремий сусідній елемент:

const items = ['Children 1', 'Children 2'];

<div className="container">
  {items.map(item => (
    <div key={item}>{item}</div>
  ))}
  <div>Children 3</div>
</div>

У підсумку обʼєкт елемента матиме такий вигляд. Зверніть увагу на синтаксис children:

{
  type: "div",
  key: null,
  props: {
    className: "container",
    children: [
      [
        { type: "div", key: null, props: ... },
        { type: "div", key: null, props: ... }
      ],
      { type: "div", key: null, props:  ... }
    ]
  }
}

Урешті ми отримуємо масив не з трьох, а двох елементів: перший — це динамічний список, згенерований за допомогою методу map(), а другий — статичний елемент, доданий окремо.

Цей приклад ілюструє, як React розрізняє статичні сусідні елементи й динамічні списки, додані за допомогою масиву даних та методу map().

Така поведінка React цілком логічна, бо записані поряд елементи — скільки б їх не було — не можуть бути динамічно змінені через сортування, додавання чи видалення. Вони абсолютно статичні та не можуть зазнати жодних змін, окрім як у самому коді.

Натомість використання масиву даних та методу map() навпаки говорить про те, що цей список буде динамічним. Цілком імовірно, що порядок або кількість елементів у ньому може змінюватись. React прагне робити це з мінімальними оновленнями реального DOM, і атрибут key відіграє в цьому ключову роль.

Роль key у динамічних списках

Філософія React полягає в тому, щоб оновлювати DOM тільки там, де це потрібно. Проте динамічні списки створюють певні складнощі, бо всі елементи списку здаються React однаковими. Вони мають той самий type і відрізняються лише значеннями у props. Як тоді React визначає, який елемент потрібно оновити? Відповідь — за допомогою унікального значення атрибута key.

Уявіть, що ви видалили пʼятий елемент зі списку, в якому key має значення індексу. Ви впевнені, що видалили елемент з індексом 4, але React цього не зрозуміє, бо елемент з таким індексом залишиться. Він побачить видалення останнього елемента списку, а також те, що для інших елементів змінилися значення в обʼєкті props. Натомість унікальний key допоможе React точно зрозуміти, який елемент було видалено зі списку.

Варто зазначити, що для атрибута key можна використовувати будь-яке унікальне значення. Якщо є масив даних, у якому немає спеціально створеного значення id, використовуйте будь-яке інше унікальне значення з масиву. В прикладі вище було взято просто текст. React не обмежує нас у виборі значення та його довжини, головне — унікальність.

Використання індексу масиву як значення key не лише небажане, але й позбавлене сенсу. React і так застосовує індекс за замовчуванням для елементів без key, але це не допомагає правильно відстежувати зміни.

Розглянемо кілька прикладів. Спочатку — приклад використання індексу масиву як значення для key. Зверніть увагу, що відбувається в DevTools.

Як бачите, видалення елемента зі списку чи додавання нового на початку списку провокує оновлення інших елементів. Це відбувається, адже для елементів змінюється індекс у масиві, а отже, і значення key. З погляду React значення key виглядають так само, але змінюється значення props, і відбувається ререндер. Це добре видно, коли елемент видаляється із середини списку — після цього оновлюються лише елементи, які йдуть після нього.

Тепер розглянемо той самий приклад, але з використанням унікального значення key.

Як бачите, додавання чи видалення елементів зі списку жодним чином не впливає на інші елементи списку. Це саме те, чого прагне React і що потрібно розробнику.

Для малих списків вплив використання index буде непомітним, однак для великих масивів з багатьма елементами це може суттєво погіршити продуктивність. Також зверніть увагу, що, коли ми змінюємо порядок, React оновлює всі елементи в списку.

Побутує міф, що додавання key допомагає уникнути зайвого ререндерингу компонентів списку. Але, очевидно, це не так. У разі зміни порядку React ререндерить їх навіть за наявності key, тому його не можна розглядати як альтернативу інструментам мемоїзації. Основне завдання key — це мінімізація непотрібних оновлень DOM саме під час роботи зі списками (додавання, видалення тощо).

Часто розробники використовують масиви та метод map() навіть для статичних списків, які не будуть змінюватися з часом, оскільки це робить код чистішим. У таких кейсах використання індексу як key цілком доцільне і не матиме жодних негативних наслідків. Хоча, на мою думку, краще ніколи не використовувати індекс як значення key.

Розглянемо ще один приклад, чому це погана ідея.

Тут є два майже однакові списки з елементами <input>. Різниця лише в значенні key. Як бачите, з додаванням нового елемента на початку списку приклад з унікальним значенням key працює саме так, як очікувалось, чого не можна сказати про використання індексу.

Як і в минулому прикладі, React не може правильно ідентифікувати окремі елементи, оскільки для кожного з них оновлюється значення key. Для React це виглядає так, наче ми просто додали ще один елемент наприкінці списку. Схематично це можна зобразити в такий спосіб:

{
  type: "form",
  key: null,
  props: {
    children: [
      { type: "input", key: "0", props: { value: "John Doe", type: "text" } },
      { type: "input", key: "1", props: { type: "text" } }
    ]
  },
  ...
}

А ось так це виглядатиме після додавання нового елемента:

{
  type: "form",
  key: null,
  props: {
    children: [
      { type: "input", key: "0", props: { value: "John Doe", type: "text" } },
      { type: "input", key: "1", props: { type: "text" } },
      { type: "input", key: "2", props: { type: "text" } },
    ]
  },
  ...
}

Натомість другий приклад, де ми використали id з унікальним значенням, матиме такий вигляд:

{
  type: "form",
  key: null,
  props: {
    children: [
      { type: "input", key: "1", props: { value: "John Doe", type: "text" } },
      { type: "input", key: "2", props: { type: "text" } }
    ]
  },
  ...
}

Такий — після додавання нового елемента:

{
  type: "form",
  key: null,
  props: {
    children: [
      { type: "input", key: "3", props: { type: "text" } },
      { type: "input", key: "1", props: { value: "John Doe", type: "text" } },
      { type: "input", key: "2", props: { type: "text" } },
    ]
  },
  ...
}

Тому використання індексу як значення атрибута key не просто негативно впливає на продуктивність, але й може спричинити небажану поведінку елементів списку.

Код та демо цього прикладу можна знайти тут: CodePen.

Приклади, які ми розглянули вище, — чи не найпоширеніші кейси використання key. Але цей атрибут може бути корисним за межами динамічних списків. Про це поговоримо далі.

Key поза списками: нестандартні кейси. State reset

Для початку розглянемо простий приклад. Уявімо, що нам необхідно у формі умовно рендерити поле вводу залежно від значення в checkbox. Скажімо, під час реєстрації ми хочемо дізнатися назву компанії, але якщо користувач вказав, що є фрилансером, тоді нам потрібне його імʼя. Спрощений вигляд такої реалізації з неконтрольованим компонентом Input буде виглядати так:

const Example = () => {
  const [isFreelancer, setIsFreelancer] = useState(false);
  
  return (
    <>
      <Checkbox label="I'm freelancer" ... />
			
      {isFreelancer ? (
	<Input label="Name" placeholder="Enter your name" />
      ) : (
	<Input label="Company" placeholder="Enter your company name" />
      )}
    </>
  )
}

Уявімо, що користувач почав вводити назву компанії, але раптом передумав та клікнув на чекбокс, щоб ввести імʼя.

Попри те, що ми рендеримо інший варіант компонента, введені дані нікуди не зникли; хоча вони нерелевантні, та користувачу доведеться їх видалити вручну. Щоб виправити це, ми можемо замінити умовний рендеринг одного з двох варіантів на рендеринг обох варіантів, але за певних умов. Це буде виглядати так:

const Example = () => {
  const [isFreelancer, setIsFreelancer] = useState(false);
  
  return (
    <>
      <Checkbox label="I'm freelancer" ... />
			
      {isFreelancer ? <Input label="Name" ... /> : null}
      {!isFreelancer ? <Input label="Company" ... /> : null}
    </>
  )
}

Різниця полягає в тому, що React не знає про умовний рендеринг і не відстежує його. Він бачить лише фінальну структуру і порівнює елементи відповідно до їхнього положення в структурі. Тому в першому прикладі children завжди містить масив із двох елементів, а залежно від умови змінюються лише дані в props.

{
  type: React.Fragment,
  key: null,
  props: {
    children: [
      { type: [Function: Checkbox], key: null, props: ... },
      { type: [Function: Input], key: null, props: { label: "Name", ...} },
    ]
  },
  ...
}

Водночас у другому прикладі масив міститиме три елементи, але один з них завжди буде null. Іншими словами, кожен з варіантів компонента Input матиме своє місце в структурі Virtual DOM, і React зможе їх відрізняти один від одного.

{
  type: React.Fragment,
  key: null,
  props: {
    children: [
      { type: [Function: Checkbox], key: null, props: ... },
      null,
      { type: [Function: Input], key: null, props: { label: "Company", ...} },
    ]
  },
  ...
}

//or

{
  type: React.Fragment,
  key: null,
  props: {
    children: [
      { type: [Function: Checkbox], key: null, props: ... },
      { type: [Function: Input], key: null, props: { label: "Name", ...} },
      null,
    ]
  },
  ...
}

Але є простіший спосіб виправити цей баг — унікальний атрибут key.

const Example = () => {
  const [isFreelancer, setIsFreelancer] = useState(false);
  
  return (
    <>
      <Checkbox label="I'm freelancer" ... />
			
      {isFreelancer ? (
	<Input key="name" label="Name" ... />
      ) : (
	<Input key="company" label="Company" ... />
      )}
    </>
  )
}

Такий метод використання атрибута key відомий як state reset. Він жодним чином не суперечить правилам React. Щобільше, це один зі способів скидання стану, який рекомендує React. Детальніше про це можна почитати в цій статті на офіційному сайті.

Розглянемо цей приклад детальніше й подивимось, що відбувається на етапі порівняння обʼєктів поточної та попередньої версії у Virtual DOM. Компоненти Input з різним значенням key у вигляді React-елементів можна відобразити так:

// isFreelancer=true
{ 
  type: [Function: Input], 
  key: "name", 
  props: { 
    label: "Name", 
    placeholder: "Enter your name", 
  } 
  ...
},

// isFreelancer=false
{ 
  type: [Function: Input], 
  key: "company", 
  props: { 
    label: "Company", 
    placeholder: "Enter your company name", 
  } 
  ...
},

Як відбувається порівняння і як саме React визначає, які зміни треба внести в DOM?

Перш за все React порівнює два елементи на рівні референсів, щоб перевірити, чи посилаються обʼєкти на одне і те саме місце в памʼяті. Якщо так, це означає, що елемент не змінився і ніяких дій виконувати не треба. Він залишиться в DOM без змін, і React його пропустить. Водночас якщо елементи не є екземплярами одного обʼєкта, це вказує, що між рендерами відбулися якісь зміни, і React переходить до більш детального порівняння.

Наступний крок — зіставлення значень type. Якщо значення різне, то старий елемент буде видалений з DOM, а новий — доданий. Якщо type однаковий, як у нашому прикладі, то це виглядає як той самий елемент, але React виконує ще одну перевірку — значення key. Це і є той ключовий момент, який розкриває потенціал атрибута key за межами динамічних списків.

Якщо значення key однакове або відсутнє, то виконується ререндер, що і відбулося в першому прикладі. React просто оновив наявний елемент з новими даними, зберігши зв’язок із відповідним елементом у реальному DOM. Це означає, що всі дані, введені користувачем, залишаються прив’язаними до цього DOM-елемента. Тому після кліку на чекбокс користувач бачить не порожнє поле вводу, а введені раніше дані.

Якщо ж значення key відрізняється, то React розцінює це як абсолютно новий елемент і замість ререндеру виконує видалення старого елемента і додавання нового.

На практиці цей приклад малоймовірний, адже в більшості випадків використовуються контрольовані компоненти. Водночас це чудова ілюстрація, як можна певним чином контролювати поведінку React на етапі reconciliation додаванням лише одного атрибута key. Приклад коду — за посиланням.

Використання key з анімаціями

Розглянемо ще один простий, але доволі поширений приклад використання табів. До контенту кожного табу додано класичну анімацію появи, яка спрацьовує щоразу після перемикання. Контент — це єдиний компонент, який приймає зображення, заголовок та текст як props, що змінюються з перемиканням табу.

Нижче на відео можна порівняти поведінку з атрибутом key та без нього. У коді виклик компонента з контентом виглядає ось так.

{hasKey ? (
  <ContentCard key={activeContent.id} activeContent={activeContent} />
) : (
  <ContentCard activeContent={activeContent} />
)}

Весь код цього прикладу можна знайти в GitHub-репозиторії.

Як бачите, за наявності атрибута key під час кожного перемикання табу React чітко розуміє, що це різні екземпляри компонента ContentCard, видаляє старий і додає новий замість ререндеру. Внаслідок цього анімація працює в передбачений спосіб. Якщо key відсутній, поведінка компонента вже не така, як очікувалось, бо React оновлює наявний елемент, виконуючи ререндер з новими даними в обʼєкті props. У цей самий момент для компонента починає працювати анімація появи й це виглядає як блимання контенту.

Виправляємо специфічний баг за допомогою key

Наостанок хотів показати ще один специфічний приклад багу, який вдалося легко вирішити за допомогою атрибута key. Він був повʼязаний з кнопкою, відтворювався тільки на iOS-пристроях і тільки в in-app браузері Facebook. Кнопка розміщувалася на статичному сайті (SSG), створеному на Next.js 14, який за замовченням був англійською, а локалізація іншими мовами реалізована через значення пошукового параметра.

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

Найпростішим способом виправити цей баг було додати до кнопки атрибут key, а як унікальне значення — локаль з пошукових параметрів.

Це доволі специфічний баг, і шансів натрапити на нього не так багато. Однак він чудово ілюструє, наскільки важливо розуміти механізм роботи key у React.

Визначити всі ймовірні ситуації, де state reset може стати в пригоді, неможливо. Однак key — це потужний інструмент, який має бути в арсеналі кожного розробника та іноді може заощадити чимало часу на дебагінгу та пошуку розв’язання специфічних проблем.

Сподіваюсь, стаття була корисною. Головною метою було привернути увагу до атрибута key. Він має широкі можливості, але іноді про нього забувають або хибно асоціюють тільки зі списками.

Я поділився лише двома прикладами, з якими стикався особисто. Проте знаю, що є чимало інших цікавих сценаріїв використання key — навіть як «костиль» для обходу агресивного кешування в Next.js. Буду вдячний, якщо поділитеся своїм досвідом і прикладами в коментарях.

Дякую за ваш час! Слава Україні!

👍ПодобаєтьсяСподобалось15
До обраногоВ обраному4
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Дякую за статтю. Ви поглибили мої знання key та ще й про reconciliation більше дізнався та анімації з key.

В мене на практиці був кейс, де key пофіксив баг drag and drop.
Я використав swapy. В кінці події робив запит на сервер, щоб зберегти новий порядок елементів. Після успішного запиту у відповіді сервера був новий порядок, але на клієнті він автоматично змінювався на попередній.
Рішенням було додавання key до всього контейнеру. Я розраховував key, як id всіх елементів. І коли з сервера приходила відповідь, key ставав новим і баг, який повертав попередній стан списку зник.

Така поведінка стала для мене відправною точкою в розумінні того, що key це не просто про рендер списків.

Дякую за відгук! Радий, що стаття була корисною! І дякую, що поділились практичним кейсом. Це чудовий приклад!🔥

Корисна стаття, незаслужено мало коментарів. Сумніваюсь, що всі frontend деви чітко і системно розуміють все, що тут описано. Автор гарно все описав з прикладами коду, поясненнями, толковими інтерактивними гіфками. Читати приємно. дякую за роботу.

було б цікаво почути деталі історії про специфічний баг з іспансько-англійською кнопкою. Зрозуміло, що ререндер допоміг, але не дуже зрозуміло чому без ключа кнопка рендерилась наполовину.

Дякую, радий, що стаття сподобалась!🙂
Щодо багу — це дуже цікаве питання, але я, на жаль, так і не зміг зʼясувати у чому причина. Кнопка дуже проста, без якихось нових CSS-властивостей, які могли б не підтримуватись. Сам Facebook браузер, хоч і на базі WebKit, має свої особливості, тому думаю, проблема може бути в ньому. Хоча на Android багу немає, тільки на iOS. Припускаю, що це щось на рівні взаємодії самої ОС із Facebook браузером, але це лише припущення.🤷‍♂️

до речі ДОУ охренів — тут досі не можна ні видалити, ні відредагувати коментар. я б наприклад хотів прибрати кілька зайвих знаків питання з попереднього коментаря, бо воно виглядає надто емоційно.

Часто розробники використовують масиви та метод map() навіть для статичних списків, які не будуть змінюватися з часом, оскільки це робить код чистішим. У таких кейсах використання індексу як key цілком доцільне і не матиме жодних негативних наслідків. Хоча, на мою думку, краще ніколи не використовувати індекс як значення key.

а що тоді використовувати ??? якщо є статичний список, деякі члени якого можуть навіть бути ідентичними, то що тоді ? особливо, якщо на проекті налаштований eslint і він вимагає від дева додати key

привіт! якщо елементи списку неунікальні, краще заздалегідь передбачити це і замість масиву значень створити масив обʼєктів із унікальними id для кожного елемента та використовувати їх як значення для key. Але у випадку статичних списків використання індексу теж можливе... хоча це залежить від правил в команді.

не бачу жодного сенсу створювати айді виключно для створювання айді.

в одному місці ви пишете, що НІКОЛИ не треба використовувати індекс для key
в іншому пишете, що можна. але не треба. в коментарі знов відповідаєте, що можна, але залежить.

невже не можна написати, що виключно для статичних масивів, які не містять жодного унікального ідентифікатора, можна і треба використати індекс, як key ?

бо ви ввели суворе правило, яке не у всіх випадках має сенс. хтось почитає і почне створювати айдішки для виводу простих статичних масивів. уявляю, як на них подивиться лід під час код ревю

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

завжди використовувати унікальне значення для key — це гарна звичка, яка підвищує надійність і якість коду. саме тому іноді в командах це правило закріплюють на рівні eslint, і я повністю підтримую такий підхід.

водночас я розумію вашу позицію і впевнений, що деякі розробники можуть мати іншу думку.

не створює негативних наслідків,
, я б все ж не радив цього робити

дякую вам величезне за пораду завжди створювати унікальні ідентифікатори там, де без цього можна обійтись.
пишіть ще.

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

В целом, ключи в React юзаются для эффективной работы с динамическими списками. Использование случайных или вычисляемых значений в качестве ключей может привести к непредсказуемому поведению и сложностям в отладке. Если же заюзать один и тот же ключ для разных элементов в списке. что может привести к ошибкам в отслеживании изменений.

Підписатись на коментарі