Suggest an editImprove this articleRefine the answer for “Optimizing long lists”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)Long lists are optimized primarily through **virtualization (windowing)** - rendering only the visible items plus a small "overscan", using libraries like `react-window`, `react-virtualized`, or `@tanstack/react-virtual`. **Key point:** on top of that, add pagination, memoized items with stable props, a stable `key` instead of an index, and separating heavy computation from presentation.Shown above the full answer for quick recall.Answer (EN)Image## 1) Virtualization (windowing) - a must-have We render only the visible items + a small "overscan". **Libraries:** - `react-window` (lightweight, modern) - `react-virtualized` (richer, heavier) - `@tanstack/react-virtual` (a puzzle, but flexible) **Example with** `react-window` **(fixed height):** ```javascript import { FixedSizeList as List } from 'react-window'; import React from 'react'; const Row = React.memo(({ index, style, data }: any) => { const item = data.items[index]; return ( <div style={style} onClick={() => data.onSelect(item.id)}> {item.title} </div> ); }, (prev, next) => prev.data.items[prev.index] === next.data.items[next.index]); export default function Virtualized({ items, onSelect }: { items: any[], onSelect: (id:string)=>void }) { const itemData = React.useMemo(() => ({ items, onSelect }), [items, onSelect]); return ( <List height={600} itemCount={items.length} itemSize={48} width="100%" overscanCount={6} itemData={itemData} > {Row} </List> ); } ``` **Variable height?** Use `VariableSizeList` + measure the height (for example, via `ResizeObserver`) and cache `getItemSize`. --- ## 2) Pagination and "infinite scroll" - Load data in **chunks** (limit/offset or cursor). - Render a **flat** array; new batches are **appended**. - To detect the end, use `IntersectionObserver` (no permanent scroll handlers). --- ## 3) Minimize item re-renders - Each item is a **separate memoized component**: `React.memo(Row, areEqual)`. - Item props are **stable by reference**: - handlers via `useCallback`; - complex objects/arrays via `useMemo`; - pass `itemId` instead of closing over `item` in an inline callback. - Don't use the **index as** `key` during inserts/deletes/reorders - use a stable `id`. --- ## 4) Separate computation from presentation - Filtering, sorting, aggregations - do them **once** and cache with `useMemo`. - When typing into a filter field, use `useDeferredValue` or wrap updates in `startTransition` so the list doesn't "lag": ```javascript const [query, setQuery] = React.useState(''); const deferredQuery = React.useDeferredValue(query); // smooths out filtering const filtered = React.useMemo( () => items.filter(x => x.title.includes(deferredQuery)), [items, deferredQuery] ); ``` --- ## 5) Images and heavy cells - Enable **lazy loading**: `<img loading="lazy" ... />`. - Placeholders/skeletons instead of heavy content until the data appears. - Avoid expensive DOM and complex CSS inside a cell (shadows, filters). --- ## 6) Scroll events - Don't attach a "manual" `onScroll` to the window. If you need to, use **passive listeners** and `requestAnimationFrame` + `throttle`. - With virtualization, the library already optimizes scrolling - less DIY needed. --- ## 7) The list container - Set an explicit **height**/`max-height` and `overflow: auto;` - it's easier for the browser. - For nested lists, use the CSS `contain: content;` (limits the rendering area). --- ## 8) Server rendering and hydration - For SEO/SSR of large lists, serve a **limited number of items**, load the rest on the client. - In Next.js you can stream and load chunks progressively, and virtualize on the client. --- ## 9) Size cache and DOM reuse - With variable height, keep a **measurement cache** (id → height). - Avoid fully resetting the cache on partial data changes. --- ## 10) Diagnostics - React DevTools Profiler: look for "hot" components. - Add markers to cell render logs (see `console.log('Row', index)`) locally. - Check whether you're creating new objects/functions in JSX.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.