Debugging INP in React Apps: From Field Data to Profiler
INP problems are interaction problems, not just Lighthouse scores. A slow click or keystroke can spend time in an event handler, synchronous JavaScript, React rendering, layout, and the final paint. Debugging works best when those costs are separated instead of applying memoization everywhere.
Start with a real interaction
Use field data to identify the route, device class, and interaction that users actually experience as slow. Then reproduce that exact path locally. A concrete interaction gives you a testable baseline.
Trace the main thread
Record the interaction in the browser Performance panel and inspect long tasks and the work between input and the next paint.
input
-> handler
-> state update
-> React render
-> style/layout
-> paint
If most time is spent before React renders, component memoization is unlikely to fix the bottleneck.
Reduce synchronous handler work
Keep urgent UI feedback on the critical path and move unrelated processing away from it. Large sorts, parsing, data transforms, and third-party callbacks are common sources of hidden blocking work.
For genuinely CPU-heavy processing, reduce the amount of work first; then consider caching stable results or moving suitable computation to a worker.
Use React Profiler when rendering is expensive
When the browser trace points to rendering, use React Profiler to find which subtree rendered and why. Common causes include overly broad context updates, state owned too high in the tree, unstable props that defeat existing memoization, and large lists rendered without virtualization.
memo, useMemo, and useCallback should follow evidence. They add their own complexity and do not make arbitrary JavaScript faster.
Separate urgent and non-urgent updates
A transition can keep urgent updates responsive when another React update is not immediately required:
import { startTransition } from "react"
function handleSearch(value: string) {
setInput(value)
startTransition(() => setFilter(value))
}
This changes React scheduling; it does not eliminate expensive synchronous computation.
Re-measure the same path
Write down the hypothesis before changing code, then record the same interaction again. Compare handler duration, render cost, and the time to the next paint. Validate the result on slower hardware and in field data when possible.
A useful INP workflow is simple: identify one real interaction, measure where its time goes, fix the largest verified cost, and measure again.