Списки и ключи
Списки — одна из самых частых задач. Массив данных превращается в набор элементов через map.
Базовый список
const fruits = ['Яблоко', 'Банан', 'Вишня'];
function List() {
return (
<ul>
{fruits.map((fruit) => (
<li>{fruit}</li>
))}
</ul>
);
}
Но React выдаст предупреждение: каждый элемент списка должен иметь key.
Зачем key
Когда список обновляется, React должен понять, какой элемент добавился, какой удалился, а какой переехал. Без key React сравнивает элементы по позиции — и может обновить не то, что нужно.
Правильный key
{fruits.map((fruit) => (
<li key={fruit}>{fruit}</li>
))}
key — уникальный идентификатор среди соседей. Если есть ID из БД — используй его:
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
Не используй индекс
Использование индекса массива как key — частая ошибка:
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
Проблема проявляется при сортировке, удалении, добавлении в середину: React запутается и может показать неправильные данные. Использовать индекс допустимо только для статических списков, которые никогда не меняются.
Список объектов
type User = {
id: number;
name: string;
email: string;
};
function UserList({ users }: { users: User[] }) {
return (
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} — {user.email}
</li>
))}
</ul>
);
}
Список компонентов
function CardList({ posts }: { posts: Post[] }) {
return (
<div className="grid">
{posts.map((post) => (
<Card key={post.id} post={post} />
))}
</div>
);
}
Фильтрация перед рендером
map работает вместе с filter:
{publishedPosts
.filter((post) => post.status === 'published')
.map((post) => (
<Card key={post.id} post={post} />
))}
Сортировка
{[...posts]
.sort((a, b) => a.title.localeCompare(b.title))
.map((post) => (
<Card key={post.id} post={post} />
))}
Обрати внимание на [...posts] — sort мутирует массив, а мутировать пропсы нельзя.
Пустой список
Если данных нет — покажи сообщение:
function UserList({ users }: { users: User[] }) {
if (users.length === 0) {
return <p>Пользователей нет</p>;
}
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Вложенные списки
Каждый уровень имеет свой key:
{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>
))}
Итоги
- Списки рендерятся через
map - Каждый элемент должен иметь
key key— уникальный ID, а не индекс- Фильтрация и сортировка — до
map - Пустой список нужно обрабатывать