← Назад к вопросам

Зачем нужен prop key?

1.7 Middle🔥 131 комментариев
#React

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Зачем нужен prop key?

key — это специальный prop в React, который помогает идентифицировать отдельные элементы в списке. Это критически важно для корректной работы компонентов при рендеринге динамических списков, так как React использует ключи для определения, какой элемент изменился, был добавлен или удалён.

Основная проблема без key

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

// ❌ ПЛОХО - без key
function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo, index) => (
        <li key={index}>
          {todo.text}
        </li>
      ))}
    </ul>
  );
}

Проблемы с индексом как ключом:

  • При удалении элемента индексы сдвигаются, React теряет связь
  • Состояние компонента привязывается к позиции, а не к данным
  • Фильтрация, сортировка и переупорядочение ломают структуру
  • Анимации и переходы работают неправильно

Демонстрация проблемы

// Компонент с локальным состоянием
function TodoItem({ text, initialId }) {
  const [isChecked, setIsChecked] = useState(false);
  
  return (
    <li>
      <input 
        type="checkbox" 
        checked={isChecked} 
        onChange={(e) => setIsChecked(e.target.checked)}
      />
      {text}
    </li>
  );
}

// Использование без нормального key
function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo, index) => (
        <TodoItem key={index} text={todo.text} />
      ))}
    </ul>
  );
}

// ПРОБЛЕМА:
// 1. Добавили новый элемент в начало списка
// 2. React переиспользует компоненты по индексу
// 3. Состояние (isChecked) сохранилось на неправильный элемент
// 4. Чекбоксы показывают неправильные значения

Правильное использование key

// ✅ ХОРОШО - используем уникальный идентификатор
function TodoItem({ id, text }) {
  const [isChecked, setIsChecked] = useState(false);
  
  return (
    <li>
      <input 
        type="checkbox" 
        checked={isChecked} 
        onChange={(e) => setIsChecked(e.target.checked)}
      />
      {text}
    </li>
  );
}

function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => (
        <TodoItem 
          key={todo.id}  // Уникальный идентификатор
          id={todo.id}
          text={todo.text} 
        />
      ))}
    </ul>
  );
}

Как работает key

React использует ключи для:

1. Идентификации элементов

// До изменения
[{ id: 1, text: 'Task 1' }, { id: 2, text: 'Task 2' }]

// После добавления в начало
[{ id: 3, text: 'Task 3' }, { id: 1, text: 'Task 1' }, { id: 2, text: 'Task 2' }]

// React понимает:
// - Элемент с id=1 переместился (был на позиции 0, стал на позиции 1)
// - Элемент с id=2 переместился (был на позиции 1, стал на позиции 2)
// - Добавился новый элемент с id=3

2. Сохранения состояния компонента

function Item({ id, value }) {
  const [inputValue, setInputValue] = useState('');
  
  return (
    <div>
      <input 
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <span>{value}</span>
    </div>
  );
}

// С правильным key состояние (inputValue) привязано к данным
// При переупорядочении list inputValue остаётся с правильным элементом

3. Сохранения DOM элементов

function Item({ id, value }) {
  useEffect(() => {
    console.log(`Item ${id} mounted`);
    return () => console.log(`Item ${id} unmounted`);
  }, [id]);
  
  return <div>{value}</div>;
}

// С правильным key:
// - При сортировке/фильтрации React переиспользует DOM элементы
// - useEffect срабатывает при действительном монтировании/размонтировании

Практический пример: фильтрация списка

function User({ id, name }) {
  const [isOnline, setIsOnline] = useState(false);
  
  return (
    <div className="user-card">
      <h3>{name}</h3>
      <button onClick={() => setIsOnline(!isOnline)}>
        {isOnline ? 'Online' : 'Offline'}
      </button>
    </div>
  );
}

function UserList() {
  const [users] = useState([
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' },
    { id: 3, name: 'Charlie' }
  ]);
  
  const [search, setSearch] = useState('');
  
  const filtered = users.filter(u => 
    u.name.toLowerCase().includes(search.toLowerCase())
  );
  
  return (
    <div>
      <input 
        placeholder="Search..."
        value={search}
        onChange={(e) => setSearch(e.target.value)}
      />
      <div>
        {filtered.map(user => (
          <User 
            key={user.id}  // ✅ Уникальный id, не индекс
            id={user.id}
            name={user.name}
          />
        ))}
      </div>
    </div>
  );
}

// Без key:
// - Вводишь "Bob"
// - Видишь только User с id=2
// - Его состояние (isOnline) может быть испорчено
// - Эффекты срабатывают неправильно

// С key={user.id}:
// - Вводишь "Bob"
// - Видишь только User с id=2
// - Его состояние сохранено правильно
// - Эффекты работают корректно

Требования к хорошему key

// ✅ ХОРОШИЕ ВАРИАНТЫ:
key={item.id}              // Уникальный ID из базы
key={item.uuid}            // UUID генерированный на сервере
key={`${item.parentId}_${item.id}`}  // Составной ключ для вложенных структур

// ❌ ПЛОХИЕ ВАРИАНТЫ:
key={index}                // Индекс массива
key={Math.random()}        // Random - новый ключ при каждом рендере
key={item.name}            // Неуникальный (два пользователя могут быть named Alice)

Когда key не нужен

// ✅ Статический список без операций
function StaticList() {
  return (
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>
  );
}

// ✅ Список не изменяется
const items = ['A', 'B', 'C']; // Константа
{items.map(item => <div>{item}</div>)} // key не критичен

Итоги

  • key помогает React идентифицировать элементы в списках
  • Без правильного key компоненты работают неправильно при изменении порядка/фильтрации
  • Используй уникальный идентификатор из данных, не индекс
  • Правильный key сохраняет состояние и эффекты в правильных элементах
  • Это особенно важно для интерактивных компонентов с локальным состоянием
Зачем нужен prop key? | PrepBro