← Назад к вопросам
Какие знаешь способы оптимизации длинных списков?
1.0 Junior🔥 121 комментариев
#Оптимизация и производительность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Оптимизация длинных списков в React
Это критическая задача при работе с большими наборами данных. Существует несколько эффективных подходов.
1. Виртуализация (Virtualization)
Основной метод — рендерить только видимые элементы DOM. Используйте библиотеки:
- react-window — самая легковесная
- react-virtual — современная альтернатива
- TanStack Virtual — новый стандарт
import { useVirtualizer } from "@tanstack/react-virtual";
export function VirtualList({ items }) {
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 35,
overscan: 10,
});
return (
<div ref={parentRef} style={{ height: "600px", overflow: "auto" }}>
<div style={{ height: virtualizer.getTotalSize() }}>
{virtualizer.getVirtualItems().map((virtualItem) => (
<div key={virtualItem.key} data-index={virtualItem.index}>
{items[virtualItem.index].name}
</div>
))}
</div>
</div>
);
}
2. Пагинация и бесконечный скролл
Пагинация: делит список на страницы, пользователь переходит вручную.
Бесконечный скролл: автоматически загружает новые данные при прокрутке.
function InfiniteList() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(0);
const [hasMore, setHasMore] = useState(true);
const loadMore = async () => {
const newItems = await fetchItems(page);
setItems((prev) => [...prev, ...newItems]);
setPage((p) => p + 1);
if (newItems.length < 20) setHasMore(false);
};
useEffect(() => {
const handleScroll = (e) => {
const { scrollTop, scrollHeight, clientHeight } = e.target;
if (scrollHeight - scrollTop < 500 && hasMore) {
loadMore();
}
};
// Attach listener
}, [hasMore, page]);
return <div>{items.map((item) => <ItemComponent key={item.id} item={item} />)}</div>;
}
3. Мемоизация и useMemo
Применяйте React.memo для элементов списка и useMemo для вычислений:
const ListItem = React.memo(({ item, onClick }) => (
<div onClick={() => onClick(item.id)}>
{item.name} — {item.price}
</div>
), (prevProps, nextProps) => {
return prevProps.item.id === nextProps.item.id &&
prevProps.onClick === nextProps.onClick;
});
function FilteredList({ items, filter }) {
const filtered = useMemo(
() => items.filter((item) => item.name.includes(filter)),
[items, filter]
);
return filtered.map((item) => <ListItem key={item.id} item={item} />);
}
4. Lazy Loading изображений
Для списков с изображениями используйте Intersection Observer API:
function LazyImage({ src, alt }) {
const [isVisible, setIsVisible] = useState(false);
const ref = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.unobserve(entry.target);
}
},
{ threshold: 0.1 }
);
if (ref.current) observer.observe(ref.current);
return () => observer.disconnect();
}, []);
return <img ref={ref} src={isVisible ? src : ""} alt={alt} loading="lazy" />;
}
5. Оптимизация на уровне DOM
- Key props: используйте уникальные, стабильные ID, не индексы
- Ключи по индексам приводят к переренденрингу при удалении/добавлении элементов
- debounce/throttle для обработчиков скролла
- CSS containment:
contain: layout paintограничивает переход к родительским элементам
6. Профилирование и мониторинг
Используйте React DevTools Profiler:
- Найдите компоненты с лишними ре-рендерами
- Проверьте Chrome DevTools Performance tab
- Ищите долгие Task блокирующие основной поток
Рекомендация на практике
Для 10,000+ элементов комбинируйте:
- Виртуализация (react-virtual)
- Lazy loading для медиа
- Пагинация на сервере для снижения трафика
- Мемоизация критических компонентов
- Web Workers для фильтрации/сортировки больших наборов
Этот подход обеспечит smooth 60fps даже с тысячами элементов.