Skip to main contentblog
back to blog

react performance: small wins that matter

19 oct 2025, 10:14 utc+8·1 min read
share:

the problem with premature optimization

before you optimize, measure. react is fast enough for most use cases.

but when things get slow, here are patterns that actually help.

memo when it counts

don't wrap everything in React.memo. use it for expensive components that receive stable props.

const ExpensiveList = React.memo(({ items }: { items: Item[] }) => {
  return (
    <div>
      {items.map(item => (
        <ExpensiveItem key={item.id} data={item} />
      ))}
    </div>
  )
})

callback stability

unstable callbacks break memoization. useCallback fixes this.

const handleClick = useCallback((id: string) => {
  updateItem(id)
}, [updateItem])

lazy load what you can

code splitting is free performance. use it.

const HeavyChart = dynamic(() => import('./heavy-chart'), {
  loading: () => <Skeleton />,
})

virtual lists for long data

rendering 10,000 items? use react-window or @tanstack/virtual.

import { useVirtualizer } from '@tanstack/react-virtual'
 
const virtualizer = useVirtualizer({
  count: items.length,
  getScrollElement: () => parentRef.current,
  estimateSize: () => 35,
})

measure with profiler

use react devtools profiler. find what's actually slow.

most performance issues come from:

  • unnecessary re-renders
  • expensive calculations on every render
  • too much work in render phase

fix those first.

contents
  • the problem with premature optimization
  • memo when it counts
  • callback stability
  • lazy load what you can
  • virtual lists for long data
  • measure with profiler