All posts

Stop Hand-Optimizing Renders: Living With the React Compiler

ReactJavaScriptDeveloper ExperienceProductivity

Turning the compiler on is a five-minute config change. Changing how you write components is the real migration.

The habit you need to unlearn

A generation of React developers learned a reflex: see a function or object created in render, reach for useMemo or useCallback. With the compiler doing memoization automatically, that reflex is now mostly counterproductive — it adds noise the compiler would have handled, and occasionally fights it.

The new default is to write the obvious code and let the toolchain optimize it.

// Old reflex
const handleClick = useCallback(() => save(id), [id])
const columns = useMemo(() => buildColumns(schema), [schema])

// With the compiler
const handleClick = () => save(id)
const columns = buildColumns(schema)

What stays your job

The compiler optimizes; it does not fix design. These remain firmly human:

  • Data fetching strategy — what loads when, and where the suspense boundaries sit.
  • Component boundaries — splitting a 400-line component is still your call.
  • Genuinely expensive work — a heavy computation may still deserve to move off the render path entirely (a web worker, a cache, the server).

Automatic memoization makes cheap re-renders free. It does not make a bad architecture fast.

Migrating an existing codebase

A pragmatic order of operations:

  1. Enable the compiler and ship it — it is conservative and safe by default.
  2. Fix lint violations first. The new rules flag impure render logic; these are the patterns that both break the compiler and hide real bugs.
  3. Remove manual memoization gradually, file by file, profiling as you go rather than in one giant sweep.
  4. Leave useMemo where it is load-bearing for correctness — e.g. preserving referential identity for a dependency array you control deliberately. The compiler handles performance, not your intentional semantics.

How to tell it is working

Use the React DevTools profiler before and after. You are looking for fewer wasted renders without any new ones. If a component stopped updating when it should, that is almost always a purity violation the compiler exposed — fix the cause, do not paper over it.

The mindset shift

This is the same move we have seen everywhere in 2026: low-level mechanical work gets automated, and human attention moves up the stack to judgment. You stop spending Friday afternoons hunting for the missing dependency in a useMemo array and start spending it on whether the component should exist in that shape at all.

Cleaner code, less ceremony, fewer footguns. Let the compiler do the bookkeeping.

More on modern frontend architecture on the blog. →