Key в React: как сохранить состояние строки при сортировке

Key в React: как сохранить состояние строки при сортировке
Содержание статьи

В изменяемом списке React ключом обычно должен быть стабильный идентификатор записи, например key={item.id}. Индекс обозначает место в массиве. После сортировки это место может занять другая запись, а локальное состояние компонента останется связано с прежней позицией.

На Mentoring.digital разберём проблему через редактируемую заметку у задачи. Такой пример показывает смысл key лучше, чем устранение предупреждения в консоли без проверки поведения.

Список с состоянием внутри строки

import { useState } from "react";

const initial = [
  { id: "task-a", name: "Проверить форму" },
  { id: "task-b", name: "Исправить меню" },
  { id: "task-c", name: "Обновить текст" }
];

function Row({ item }) {
  const [note, setNote] = useState("");
  return (
    <li>
      <span>{item.name}</span>
      <input
        aria-label={"Заметка: " + item.name}
        value={note}
        onChange={event => setNote(event.target.value)}
      />
    </li>
  );
}

export default function Tasks() {
  const [items, setItems] = useState(initial);
  return (
    <section>
      <button type="button" onClick={() =>
        setItems(current => [...current].reverse())
      }>Развернуть список</button>
      <ul>{items.map(item =>
        <Row key={item.id} item={item} />
      )}</ul>
    </section>
  );
}

Поместите компонент в учебное React-приложение. Введите заметку в строку «Проверить форму», затем разверните список. При стабильном task-a заметка должна остаться рядом с той же задачей, хотя её позиция изменилась.

В отдельной учебной копии замените выражение map на items.map((item, index) => <Row key={index} item={item} />). Повторите действие. Теперь индекс связывает компонент с местом, и заметка может оказаться рядом с другой задачей. Это ошибка идентичности строки, а не ошибка сортировки самого массива.

Откуда брать устойчивый идентификатор

Если запись пришла с сервера, используйте её подходящий уникальный ID. Для локально создаваемой записи сформируйте идентификатор в момент создания и сохраните вместе с данными. Не создавайте новый случайный ключ при каждом рендере.

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

Ключи должны различаться среди соседних элементов одного списка. Глобальная уникальность во всём приложении не требуется. Сам key не приходит в компонент как обычный prop: если строке нужен ID для обработчика, передайте его отдельно или через item, как в нашем примере.

Ключ сохраняет связь, но не хранит всё состояние навсегда

Если удалить строку из дерева, её локальное состояние уничтожается. Повторное добавление записи с тем же ID не восстанавливает уже удалённую заметку автоматически. Когда заметки должны переживать фильтрацию или размонтирование, храните их на подходящем уровне, например в родительском состоянии по ID.

Изменение key можно использовать намеренно для сброса компонента. Но случайный ключ делает такой сброс на каждом рендере: теряются введённые значения, создаются новые компоненты. Это не способ ускорить список.

Индекс не превращается в ошибку во всех возможных статичных списках. Риск появляется, когда состав или порядок меняется и внутри элементов важна идентичность. Для редактируемого каталога лучше сразу выбирать ключ из данных и проверять реальные операции пользователя.

Проверка списка перед передачей

  • Заметка остаётся у своей задачи после сортировки.
  • Вставка новой записи в начало не переносит состояние соседних строк.
  • Удаление одной записи не меняет заметки остальных.
  • Одинаковые названия с разными ID не конфликтуют.
  • После фильтрации поведение заметок соответствует выбранному месту хранения.

Не вызывайте reverse непосредственно на массиве состояния: пример сначала делает копию. Самостоятельно добавьте удаление и вставку, затем проверьте те же сценарии. Это полезное упражнение для обучения Frontend-разработке. Если ошибка проявляется только в сложном компоненте, ментору по Frontend стоит показать небольшой список с одним редактируемым полем и точной последовательностью действий.

Похожие статьи по данной теме