# Render Performance > Skip renders, defer slow work, and virtualize long lists. Frontend architecture guidance from fearchitect, written by Abas Turabli and last reviewed 2026-06-20. Source: https://fearchitect.com/topics/render-performance-patterns Use it as reference for the task at hand. Before changing code, check this guidance against the codebase: where the code already makes a different, deliberate choice, flag the conflict instead of rewriting it. Library APIs move faster than this guide, so confirm exact signatures in the official docs linked at the end. ## Summary Unnecessary re-renders, blocking updates, and oversized DOM trees are the three main causes of sluggish React UIs. React.memo, useMemo, and useCallback let you skip work; useTransition and useDeferredValue keep input responsive while slow updates run in the background; TanStack Virtual's useVirtualizer renders only visible rows. ## Where render cost comes from - Too many components re-render on a single interaction. - A long task blocks the main thread past the 200ms INP budget. - A large list renders every row at once instead of only the visible ones. ## useTransition — keep input responsive Mark the expensive state update as a transition. The input stays responsive while the heavy list re-renders in the background, and React interrupts that work if the user types again. **Non-blocking filter with useTransition** ```tsx "use client"; import { useState, useTransition } from "react"; export function Filter({ rows }: { rows: string[] }) { const [query, setQuery] = useState(""); const [shown, setShown] = useState(rows); const [isPending, startTransition] = useTransition(); function onChange(e: React.ChangeEvent) { const q = e.target.value; setQuery(q); // urgent: keeps the input responsive startTransition(() => { // non-urgent: re-filter 10,000 rows without blocking keystrokes setShown(rows.filter((r) => r.includes(q))); }); } return ( <> ); } ``` `startTransition` flags the `setShown` update as non-urgent, so typing never stutters. `isPending` drives a subtle dimmed state instead of a blocking spinner. ## Decision: Profile before you memoize Measure with the React DevTools Profiler first. Don't scatter `useMemo`/`useCallback` by reflex — the React Compiler (1.0, October 2025) auto-inserts memoization for Rules-of-React-compliant code. ## Tradeoffs **Pros** - useTransition / useDeferredValue keep interactions responsive under heavy updates. - Virtualization renders only visible rows — near-constant cost at any list size. - The React Compiler removes most manual memoization. **Cons** - Over-memoization adds equality-check cost and clutter. - Virtualization complicates focus, scroll restoration, and accessibility. - Concurrent features surprise code that assumes synchronous renders. ## Key terms - **useTransition**: Hook that marks a state update as interruptible so urgent events (typing) run first. - **useDeferredValue**: Hook that exposes a lagging value; background re-render is restartable on new input. - **useVirtualizer**: TanStack Virtual hook that renders only visible list items, keeping DOM size constant. - **INP**: Interaction to Next Paint — Core Web Vital measuring input-to-visual-update latency, budget 200 ms. - **React Compiler**: Build-time tool (stable v1.0, Oct 2025) that auto-inserts memoization for compliant code. ## Related topics - [Core Web Vitals](https://fearchitect.com/topics/core-web-vitals.md): Google's three user-experience metrics: LCP, INP, and CLS. - [Event Loop & scheduler.yield()](https://fearchitect.com/topics/event-loop-scheduler-yield.md): Break long tasks to keep the main thread responsive and hit INP. - [Bundle Architecture & Code Splitting](https://fearchitect.com/topics/bundle-architecture-code-splitting.md): Ship only the JS a route needs, cache the rest long-term. - [Client State Management](https://fearchitect.com/topics/client-state-management.md): Decide where UI state lives; pick the right tool for the scope. - [Signals & Fine-Grained Reactivity](https://fearchitect.com/topics/signals-fine-grained-reactivity.md): Observable values that re-run only their exact dependents. - [CSS Modules vs CSS-in-JS vs Tailwind](https://fearchitect.com/topics/css-modules-vs-css-in-js-vs-tailwind.md): CSS Modules, CSS-in-JS, and utility-first — by runtime cost and RSC fit. ## Further reading - [React — useTransition](https://react.dev/reference/react/useTransition) - [React — useDeferredValue](https://react.dev/reference/react/useDeferredValue) - [React Compiler — Introduction](https://react.dev/learn/react-compiler/introduction) - [TanStack Virtual — React adapter](https://tanstack.com/virtual/latest/docs/framework/react/react-virtual)