Member-only story
I rendered 50,000 rows four ways in React 19. React.memo cut one update from 349 ms to 27 ms, and virtualisation to under 5 ms
I rendered the same list of 50,000 rows with a plainmap, with React.memo rows, with react-window and with TanStack Virtual, and measured mounting, updating one row and an unrelated parent update. React.memo made updates about 13x cheaper (349 ms to 27 ms for one changed row) but did nothing for mounting, which stayed at 5.1 seconds. The two virtualised lists mounted in 16 and 24 ms, held 116 DOM nodes instead of 250,005, and updated in under 5 ms. This is jsdom, not a browser, so read the milliseconds as a ranking and not as what a phone will do.
How I tested
Node 22.22.0 on a 2-core sandbox, React and React DOM 19.3.1, react-window 2.5.3, @tanstack/react-virtual 3.14.25, jsdom 26.1.0. It's the same kind of harness as in my last article: a counter inside each row component, act() in the development build for render counts, and the production build with flushSync for timings.
A row is a div with three spans and a button, so 5 DOM nodes. The list lives in a parent component that owns the items array in state, plus a separate tick state that has nothing to do with the rows.
- Plain:
items.map((it) => <Row key={it.id} item={it} />).










