Отрисовывал ли список с помощью функции map
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Отрисовывал ли список с помощью функции map?
Да, активно использую функцию map() при отрисовке списков в React. Это один из самых важных паттернов в фронтенд-разработке, который нужно применять для динамического создания элементов из массивов данных.
Основной принцип
map() преобразует каждый элемент массива в React-элемент:
const items = ['apple', 'banana', 'orange'];
const itemList = items.map((item, index) => (
<li key={index}>{item}</li>
));
return <ul>{itemList}</ul>;
Практические примеры
1. Список простых элементов
function ShoppingList({ items }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
const products = [
{ id: 1, name: 'Milk' },
{ id: 2, name: 'Bread' },
{ id: 3, name: 'Butter' }
];
<ShoppingList items={products} />
2. Список компонентов с данными
function UsersList({ users }) {
return (
<div className="users-grid">
{users.map((user) => (
<UserCard
key={user.id}
id={user.id}
name={user.name}
email={user.email}
avatar={user.avatar}
/>
))}
</div>
);
}
function UserCard({ id, name, email, avatar }) {
return (
<div className="user-card">
<img src={avatar} alt={name} />
<h3>{name}</h3>
<p>{email}</p>
</div>
);
}
3. Список с функциональностью
function CommentsList({ comments, onDelete, onReply }) {
return (
<div className="comments">
{comments.map((comment) => (
<Comment
key={comment.id}
comment={comment}
onDelete={() => onDelete(comment.id)}
onReply={() => onReply(comment.id)}
/>
))}
</div>
);
}
function Comment({ comment, onDelete, onReply }) {
return (
<div className="comment">
<p>{comment.text}</p>
<small>{comment.author}</small>
<button onClick={onReply}>Reply</button>
<button onClick={onDelete}>Delete</button>
</div>
);
}
Критически важный момент: KEY
Всегда используй уникальный key, а не index. Это критическая ошибка в React:
// Плохо - используем index как key
{items.map((item, index) => (
<li key={index}>{item.name}</li>
))}
// Хорошо - используем уникальный идентификатор
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
Почему это важно?
Когда ты используешь index как key, и элементы переупорядочиваются или удаляются, React может спутать компоненты и их состояние:
// Исходный список
[
{ id: 1, text: 'Learn React', done: false },
{ id: 2, text: 'Build app', done: true }
]
// После удаления первого элемента
[
{ id: 2, text: 'Build app', done: true }
]
// С index key — React думает, что первый элемент всё ещё там
// С id key — React понимает, что это второй элемент, и состояние сохраняется
Методы рендеринга списков
1. Inline map
function ProductList({ products }) {
return (
<ul>
{products.map((product) => (
<li key={product.id}>{product.name} - ${product.price}</li>
))}
</ul>
);
}
2. Методы массива перед map
// Отфильтровать перед отрисовкой
function ActiveTodos({ todos }) {
return (
<ul>
{todos
.filter((todo) => !todo.completed)
.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}
// Отсортировать перед отрисовкой
function SortedComments({ comments }) {
return (
<div>
{comments
.sort((a, b) => b.likes - a.likes)
.map((comment) => (
<Comment key={comment.id} comment={comment} />
))}
</div>
);
}
// Преобразовать перед отрисовкой
function UsersList({ users }) {
return (
<ul>
{users
.map((user) => ({
...user,
fullName: `${user.firstName} ${user.lastName}`
}))
.map((user) => (
<li key={user.id}>{user.fullName}</li>
))}
</ul>
);
}
Оптимизация больших списков
1. Виртуализация с react-window
import { FixedSizeList as List } from 'react-window';
function LargeList({ items }) {
return (
<List
height={600}
itemCount={items.length}
itemSize={35}
width="100%"
>
{({ index, style }) => (
<div style={style}>
{items[index].name}
</div>
)}
</List>
);
}
2. Пагинация
function PaginatedList({ allItems, itemsPerPage }) {
const [currentPage, setCurrentPage] = useState(1);
const startIndex = (currentPage - 1) * itemsPerPage;
const displayItems = allItems.slice(
startIndex,
startIndex + itemsPerPage
);
return (
<>
<ul>
{displayItems.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
<button onClick={() => setCurrentPage(currentPage + 1)}>
Next Page
</button>
</>
);
}
Распространённые ошибки
1. Функции в map без key
// Плохо
{items.map((item) => (
<div onClick={() => console.log(item)}>
{item.name}
</div>
))}
// Хорошо
{items.map((item) => (
<div key={item.id} onClick={() => console.log(item)}>
{item.name}
</div>
))}
2. Отсутствие обработки пустого списка
// Плохо
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
// Хорошо
{items.length === 0 ? (
<p>No items found</p>
) : (
items.map((item) => (
<li key={item.id}>{item.name}</li>
))
)}
3. Сложные вычисления внутри map
// Плохо - вычисления внутри рендера
{items.map((item) => (
<div key={item.id}>
{expensiveCalculation(item)}
</div>
))}
// Хорошо - вычисли заранее или используй useMemo
const processedItems = useMemo(() => {
return items.map(item => ({
...item,
processed: expensiveCalculation(item)
}));
}, [items]);
{processedItems.map((item) => (
<div key={item.id}>{item.processed}</div>
))}
Реальный пример из проекта
function QuestionsList({ questions, onSelectQuestion }) {
return (
<div className="questions">
{questions.length === 0 ? (
<EmptyState message="No questions found" />
) : (
<ul className="questions-list">
{questions.map((question) => (
<li key={question.id} className="question-item">
<QuestionCard
question={question}
onClick={() => onSelectQuestion(question.id)}
/>
</li>
))}
</ul>
)}
</div>
);
}
Заключение
map() — это фундаментальный паттерн в React для отрисовки динамических списков. Правильное использование с уникальными keys, обработкой пустых списков и оптимизацией больших данных — это признак профессионального кода. Каждый день я использую этот паттерн в своих проектах, и это одна из первых вещей, которые нужно освоить при изучении React.