• Home
  • About
  • Agent Skills
  • Projects
  • Blog
  • Contact
Resume
Naser Rasouli

Author

Naser Rasouli

Front-End developer - sharing lessons learned, notes, and write-ups from real projects.

GitHubLinkedIn

Last posts

Optimistic UI in React Without the Common Bugs
2026-09-11•1 min read

Optimistic UI in React Without the Common Bugs

A practical React optimistic UI pattern using useOptimistic, transitions, failure recovery, and server reconciliation without duplicating authoritative state.

JavaScript SEO for React: What Google Actually Sees
2026-09-10•1 min read

JavaScript SEO for React: What Google Actually Sees

A practical React SEO guide to crawling, rendering, indexing, SSR and prerendering, internal links, metadata, and client-rendered content.

Type-Safe React Forms with React Hook Form and Zod
2026-09-07•1 min read

Type-Safe React Forms with React Hook Form and Zod

A schema-first approach to React forms with React Hook Form and Zod, covering inferred types, field arrays, API errors, conditional fields, and client/server validation boundaries.

Debugging INP in React Apps: From Field Data to Profiler

Debugging INP in React Apps: From Field Data to Profiler

2026-09-10
reactperformanceinpweb-vitalsprofiling

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.