- Главная
- Javascript
- Как React работает со списками данных и ключами
Как React работает со списками данных и ключами
Содержание
- Введение: зачем нужны списки в React
- Базовый рендеринг списка с
.map() - Что такое
keyи зачем он нужен - Правила выбора
key - Пример с динамическим списком (To-Do)
- Работа с пустыми списками
- Фильтрация и сортировка списков
keyвложенных списковkeyи производительность- Альтернативы
.map()для списков - Частые ошибки новичков
- Итог (что мы узнали)
- Задание для закрепления (на 1–2 часа)
- Что дальше?
Цель урока: научиться отображать массивы данных в React: превращать список объектов в элементы интерфейса, правильно использовать ключи (key) для оптимизации производительности и эффективно управлять динамическими списками.
Введение: зачем нужны списки в React
Любое современное приложение работает со списками:
- Список товаров в интернет-магазине
- Список сообщений в чате
- Список пользователей в админке
- Список задач в To-Do приложении
Главная мысль:
React не имеет специального синтаксиса для списков. Всё делается через метод массива .map(), который превращает данные в JSX-элементы.
Базовый рендеринг списка с .map()
Синтаксис:
{массив.map((элемент, индекс) => (
<JSX-элемент key={уникальный_идентификатор}>
{элемент}
</JSX-элемент>
))}
Простейший пример:
function FruitList() {
const fruits = ['Яблоко', 'Банан', 'Апельсин'];
return (
<ul>
{fruits.map((fruit) => (
<li key={fruit}>{fruit}</li>
))}
</ul>
);
}
// Результат:
// • Яблоко
// • Банан
// • Апельсин
Пример с объектами:
function UserList() {
const users = [
{ id: 1, name: 'Алексей', age: 25 },
{ id: 2, name: 'Мария', age: 30 },
{ id: 3, name: 'Иван', age: 28 }
];
return (
<div>
{users.map((user) => (
<div key={user.id}>
<h3>{user.name}</h3>
<p>Возраст: {user.age}</p>
</div>
))}
</div>
);
}
Что такое key и зачем он нужен
Key — это специальный атрибут, который React использует для идентификации элементов в списке.
Зачем он нужен?
- React отслеживает, какие элементы изменились, добавились или удалились
- Без
keyReact будет пересоздавать все элементы при любом изменении - С
keyReact обновляет только те элементы, которые действительно изменились
Как это работает:
// Без key (плохо ❌)
{users.map((user) => (
<li>{user.name}</li>
))}
// С key (хорошо ✅)
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
Правила выбора key
Каким должен быть key:
- Уникальным среди элементов одного списка
- Стабильным (не меняется между рендерами)
- Предсказуемым
Что можно использовать как key:
| Вариант | Пример | Подходит? |
|---|---|---|
| ID из базы данных | key={user.id} |
✅ Отлично |
| Уникальный индекс (только если статичный список) | key={index} |
⚠️ С осторожностью |
| Уникальная строка | key={email} |
✅ Можно |
| Случайное число | key={Math.random()} |
❌ Никогда |
Почему index — не всегда хороший выбор:
// Проблема с index
const todos = ['Купить хлеб', 'Позвонить маме', 'Сделать уроки'];
{todos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
// Если удалить первый элемент, остальные получат новые индексы
// React пересоздаст их все, а не обновит
Оживи свой сайт. Освой JavaScript!
Статичная верстка — это только скелет. Наш онлайн-курс "JavaScript с нуля до профи" даст твоим страницам мышцы и нервы. Научись создавать слайдеры, формы, интерактивные карты и получать данные с сервера.
От теории — к реальным скриптам в твоём портфолио.
Пример с динамическим списком (To-Do)
Полноценный пример работы со списком:
import { useState } from 'react';
function TodoList() {
const [tasks, setTasks] = useState([
{ id: 1, text: 'Купить хлеб', done: false },
{ id: 2, text: 'Позвонить маме', done: true },
{ id: 3, text: 'Сделать уроки', done: false }
]);
const [newTask, setNewTask] = useState('');
// Добавление задачи
const addTask = () => {
if (newTask.trim() === '') return;
const newTaskObj = {
id: Date.now(), // Уникальный ID
text: newTask,
done: false
};
setTasks([...tasks, newTaskObj]);
setNewTask('');
};
// Удаление задачи
const deleteTask = (id) => {
setTasks(tasks.filter(task => task.id !== id));
};
// Переключение статуса
const toggleTask = (id) => {
setTasks(tasks.map(task =>
task.id === id ? { ...task, done: !task.done } : task
));
};
return (
<div>
<h2>Мои задачи</h2>
<input
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
placeholder="Новая задача..."
/>
<button onClick={addTask}>Добавить</button>
<ul>
{tasks.map((task) => (
<li key={task.id} style={{
textDecoration: task.done ? 'line-through' : 'none'
}}>
<span onClick={() => toggleTask(task.id)}>
{task.text}
</span>
<button onClick={() => deleteTask(task.id)}>✕</button>
</li>
))}
</ul>
</div>
);
}
Работа с пустыми списками
Всегда обрабатывай случай, когда список пуст:
function ProductList({ products }) {
// Проверка на пустой массив
if (products.length === 0) {
return <p>Товаров пока нет</p>;
}
return (
<div>
{products.map((product) => (
<div key={product.id}>
<h3>{product.name}</h3>
<p>Цена: {product.price} ₽</p>
</div>
))}
</div>
);
}
Лучше с использованием тернарного оператора:
function ProductList({ products }) {
return (
<div>
{products.length === 0 ? (
<p>Товаров пока нет</p>
) : (
products.map((product) => (
<div key={product.id}>
<h3>{product.name}</h3>
<p>Цена: {product.price} ₽</p>
</div>
))
)}
</div>
);
}
Фильтрация и сортировка списков
Фильтрация перед рендерингом:
function UserList({ users, filter }) {
const filteredUsers = users.filter(user =>
user.name.toLowerCase().includes(filter.toLowerCase())
);
return (
<div>
{filteredUsers.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
Сортировка перед рендерингом:
function SortedProducts({ products }) {
const sortedProducts = [...products].sort((a, b) => a.price - b.price);
return (
<div>
{sortedProducts.map((product) => (
<div key={product.id}>
{product.name} - {product.price} ₽
</div>
))}
</div>
);
}
key вложенных списков
Если у тебя вложенные списки, каждый должен иметь свой уникальный key:
function CategoryList({ categories }) {
return (
<div>
{categories.map((category) => (
<div key={category.id}>
<h3>{category.name}</h3>
<ul>
{category.items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
))}
</div>
);
}
Важно: key должен быть уникальным внутри одного уровня. То есть элементы в разных категориях могут иметь одинаковые id.
key и производительность
Когда React использует key:
- При добавлении нового элемента в конец списка
- При удалении элемента
- При изменении порядка элементов
React с key:
// Добавляем элемент в конец
// React создаст только 1 новый элемент
const newList = [...list, newItem];
React без с key:
// Добавляем элемент в конец
// React создаст все элементы заново
const newList = [...list, newItem];
Альтернативы .map() для списков
Object.keys() для объектов:
const user = {
name: 'Алексей',
age: 25,
city: 'Москва'
};
return (
<div>
{Object.keys(user).map((key) => (
<p key={key}>{key}: {user[key]}</p>
))}
</div>
);
Object.entries() для ключ-значение:
{Object.entries(user).map(([key, value]) => (
<p key={key}>{key}: {value}</p>
))}
Частые ошибки новичков
| Ошибка | Почему | Исправление |
|---|---|---|
Нет key |
React ругается в консоли | Добавь key={user.id} |
Использование index как key |
Проблемы при сортировке/удалении | Используй уникальный ID |
key={Math.random()} |
Меняется при каждом рендере | Используй стабильный ID |
Одинаковые key в списке |
React путает элементы | Проверь уникальность |
Забыл .map() вернуть JSX |
Ошибка рендеринга | Убедись, что есть return |
Итог (что мы узнали)
| Что узнали | Как это работает |
|---|---|
| Рендеринг списков | Используем .map() для превращения данных в JSX |
key |
Уникальный идентификатор для каждого элемента |
Правила key |
Уникальный, стабильный, предсказуемый |
| Пустые списки | Обрабатываем через length === 0 |
| Фильтрация | Фильтруем перед .map() |
| Сортировка | Сортируем перед .map() |
| Вложенные списки | Каждый уровень со своим key |
Задание для закрепления (на 1–2 часа)
Создай компонент EmployeeList, который:
- Хранит список сотрудников в
state(имя, должность, отдел,id) - Отображает их в виде списка/таблицы с
key={employee.id} - Добавляет нового сотрудника через форму (имя, должность, отдел)
- Удаляет сотрудника по кнопке «Удалить»
- Фильтрует по отделу (выпадающий список: Все, Отдел 1, Отдел 2, Отдел 3)
- Сортирует по имени (кнопка «Сортировать по имени»)
Дополнительно: Добавь поиск по имени (input). Если список пуст — показывай «Сотрудники не найдены».
Проверка: Проверь, что при добавлении/удалении React правильно обновляет список и не пересоздаёт все элементы.
Пример выполнения задания
Что дальше?
В следующем уроке разберём Composition vs Inheritance — как строить сложные интерфейсы из маленьких компонентов. Ты узнаешь, почему React предпочитает композицию (сборку из частей) вместо наследования (классов), и научишься создавать гибкие и переиспользуемые компоненты. Это изменит твой подход к проектированию приложений.