InterviewsVector

React Interview Questions

From component syntax to rendering architecture

Study 111 original React interview questions across 14 connected areas. Rehearse direct answers, trace render behavior, and practice 10 production scenarios spanning performance, hydration, async races, accessibility, and frontend architecture.

Questions
111
Topics
89
Senior scenarios
10
Deep dives
18

By Mohammad Wasi

Software Engineering Leader & Technical Author · Updated August 9, 2026

Version-sensitive content reviewed .

What should I study for a React interview?

Prepare in dependency order: first understand components as pure render calculations, state as a snapshot, and identity by type, position, and key. Then study state ownership, hooks, effects as external synchronization, reconciliation, profiling, accessibility, data architecture, and testing. Senior interviews add concurrent rendering, hydration and server/client boundaries, frontend capacity, production diagnosis, and architecture that scales across teams. Strong answers trace what React does, why, the trade-off, and the user-visible consequence.

Know which layer owns the behavior

Senior candidates lose precision when they attribute closures, layout, routing, or caching to React. Debugging gets faster when the responsible layer is named before the fix.

React

Component rendering, state queues, Hooks, reconciliation, commits, Effects, Suspense, and transitions.

Ask: Which component identity and render snapshot produced this UI?

JavaScript

Closures, promises, event-loop scheduling, object identity, modules, exceptions, and CPU work.

Ask: Which lexical value, task, or promise continuation is executing?

Browser

DOM, networking, storage, accessibility tree, style, layout, paint, compositing, and input events.

Ask: Is the main thread blocked by script, layout, paint, or platform work?

Framework

Routing, loaders, caching, server rendering integration, Server Functions, deployment, and bundling policy.

Ask: Which behavior comes from the application framework rather than React itself?

Continue into the JavaScript interview hub for closures, promises, and event-loop mechanics.

Seniority changes the boundary you can reason about

Junior answers explain the component. Senior answers explain the interaction and failure. Staff answers explain the platform, ownership, capacity, migration, and organizational trade-off.

Junior

Components, props, state snapshots, JSX, event handling, lists, forms, semantic HTML, and basic Hooks.

Study this level

Mid-level

Composition, state ownership, reducers, refs, Effects, custom Hooks, context, testing, API integration, and rendering behavior.

Study this level

Senior

Reconciliation, profiling, async races, data architecture, accessibility, hydration, failure recovery, and production diagnosis.

Study this level

Staff / Principal

Frontend platforms, system boundaries, design systems, migrations, capacity, observability, performance budgets, and organizational scale.

Study this level

A React interview roadmap built on dependencies

Learn the stages in order. Performance answers are weak without the render model; Server Component answers are weak without clear client ownership; Staff answers are weak without product and team boundaries.

  1. 018 questions

    Mental model

    Render as a calculation

    Connect declarative UI, component calls, render snapshots, purity, one-way data flow, and the commit boundary.

    Outcome: Explain what React calculates, what it mutates later, and why current render values never change in place.

  2. 026 questions

    Composition

    Components & UI contracts

    Shape component boundaries, props, children, keys, controlled APIs, semantic markup, and typed interfaces.

    Outcome: Design APIs that expose intent without turning every component into a configurable framework.

  3. 037 questions

    State

    State ownership & events

    Place local, shared, server, URL, form, and cache state at the smallest correct ownership boundary.

    Outcome: Prevent duplicated truth, stale derived values, and application-wide updates caused by poor placement.

  4. 049 questions

    Hooks

    Reusable stateful behavior

    Reason about state, reducers, refs, context, memoization, custom hooks, dependencies, and closure capture.

    Outcome: Use hooks as composition primitives while keeping ownership and synchronization visible.

  5. 057 questions

    Synchronization

    Effects & external systems

    Model setup, cleanup, dependencies, races, subscriptions, timers, network work, and unnecessary effects.

    Outcome: Reserve effects for external synchronization and make every synchronization process independently correct.

  6. 068 questions

    Identity

    Rendering & reconciliation

    Trace element type, tree position, keys, state preservation, parent renders, bailouts, and host mutations.

    Outcome: Predict when state survives, resets, or moves—and separate rendering work from DOM work.

  7. 078 questions

    Evidence

    Performance diagnosis

    Use profiles, commit data, browser traces, state locality, virtualization, splitting, and bundle evidence.

    Outcome: Optimize the limiting work instead of adding memoization by reflex.

  8. 0811 questions

    Architecture

    Modern server/client React

    Distinguish concurrent rendering, transitions, Suspense, SSR, hydration, streaming, and Server Components.

    Outcome: Name which behavior belongs to React, which belongs to a framework, and where serialization and interaction boundaries sit.

  9. 0913 questions

    Product quality

    Data, forms, tests & accessibility

    Design observable data flows, resilient forms, user-centered tests, keyboard behavior, focus, and error recovery.

    Outcome: Treat correctness as user-observable behavior, including assistive technology and failure states.

  10. 1018 questions

    Systems

    Frontend system design

    Design autocomplete, large lists, real-time dashboards, modals, notifications, and form platforms end to end.

    Outcome: Connect components to data contracts, capacity, accessibility, testing, and observability.

  11. 1116 questions

    Staff+

    Platform & organizational judgment

    Evaluate design systems, microfrontends, migrations, performance budgets, governance, and multi-team boundaries.

    Outcome: Choose architecture that scales change and ownership—not merely the component tree.

Four models worth drawing in an interview

Each diagram answers a different failure class: expensive work, state that moves, callbacks that see old values, and HTML that cannot hydrate. Use the model before naming an optimization.

A state update enters the render ledger

Calculation, tree identity, host mutation, and browser paint are related—but they are not one phase.

React render lifecycleAn event queues an update. React renders and reconciles a next tree, commits host changes, then the browser paints. Render and reconcile are calculation; commit and paint are observable work.eventqueuerenderreconcilecommitpaintrestartable calculationobservable boundary
Open render deep dive

Identity decides whether state survives

Type, sibling position, and key connect one render's component to the next.

React component identityTwo rows compare a stable key, which preserves a component and its state, with a changed key, which creates a new component identity and resets state.key="ada"render Nsame identitytype + position + keystate preservedkey="grace"render N+1new identityold subtree cleans upstate resetkeys are product identity, not list decoration
Open identity deep dive

A closure belongs to one render

A callback created in render N keeps render N's values even when it runs after render N+1.

React stale closure timelineRender N creates a callback capturing count zero. Render N plus one shows count one, but the earlier callback later runs and still reads count zero.render Ncount = 0render N+1count = 1old callback runsstill reads count = 0closure retains render N's lexical values
Open closure deep dive

Hydration is a matching contract

Server HTML is reused only when the first client-rendered tree describes the same UI.

React hydration lifecycleServer rendering creates HTML displayed by the browser. JavaScript loads, React produces its first client tree, and hydration succeeds when that tree matches the HTML.server treerender to HTMLbrowser HTMLalready visiblefirst client treemust matchinteractive UIhydratesame structure · text · attributes · stable IDs
Open hydration deep dive

State is not one global bucket

State categories have different authority, lifetime, sharing, and freshness semantics. A single global-store API can hide those differences without resolving them.

Open the state taxonomy answer
01

Local UI

Component-owned interaction such as open, hover, selection, or a small draft.

02

Shared client

Client-authoritative behavior coordinated across a deliberate subtree or store.

03

Server / remote

A cached view of remote authority with freshness, invalidation, and failure rules.

04

URL

Shareable, navigable state such as query, tab, filters, and pagination.

05

Form draft

Editable, possibly invalid work that will be validated and submitted to an authority.

Modern React without release-note trivia

React 19.2 is the current stable feature series and React Compiler 1.0 is stable. Server Components are stable in React 19, while the bundler and framework APIs that implement them can change between minor versions. Framework-specific data loading and server functions are labelled explicitly.

Interview relevance comes from boundary and trade-off reasoning, not memorizing every new export.

React 19.2StableActivity, useEffectEvent, performance tracks, and server-rendering improvements.
React Compiler 1.0StableBuild-time automatic memoization with compiler-powered lint rules and incremental adoption.
Concurrent renderingStable conceptPriority-aware, interruptible render preparation—not parallel component execution.
Server ComponentsStable modelStable in React 19; framework and bundler implementation APIs remain version-sensitive.
Routing and data loadersFrameworkReact does not prescribe production routing, cache policy, or deployment integration.

What happens when React runs this?

Predict from state snapshots and component identity before revealing the render sequence. These are not trick questions; each exposes a production-relevant runtime rule.

prediction.tsx

const [count, setCount] = useState(0)

function handleClick() {
  setCount(count + 1)
  setCount(count + 1)
  setCount(count + 1)
}

After one click, what count appears?

Choose an outcome to reveal the render sequence and production consequence.

React Render Explorer

Change one architectural condition and trace what renders, what can bail out, what commits, and whether row state survives. This is a teaching model—not a Fiber simulator.

Trigger an update
Search state lives in

Component tree after the update

Query state updates in App.

Apprenders

No host node of its own

Headerrenders

No DOM change

Searchrenders

Input/results state changes

Resultsrenders

Visible result set may change

Result × 3renders

Identity and local state preserved

Footerrenders

No DOM change

Read it: Lifting query state to App expands the default render path. Results still needs the new query, so memo cannot skip it.

Common React interview myths, corrected

The correction matters more than the slogan. Each misconception collapses two different mechanisms into one convenient rule.

The Virtual DOM is always faster than the DOM.

React adds calculation so it can manage declarative updates predictably. Performance depends on the work, host mutations, DOM size, and browser behavior.

useMemo always improves performance.

It caches one calculation when dependencies repeat. It also compares dependencies, retains values, and can add stale-dependency risk.

Context replaces Redux.

Context distributes a value. State libraries may add ownership, selectors, middleware, persistence, and debugging semantics.

useEffect is React's lifecycle hook.

An Effect models one synchronization process with an external system; arbitrary mount/update logic is usually the wrong abstraction.

Every recreated function is a performance bug.

Function creation is normally cheap. Identity matters only when a measured consumer or dependency relies on it.

React.memo prevents all re-renders.

Own state and consumed Context still update a memoized component, and memo is an optimization rather than a guarantee.

Keys only remove console warnings.

Keys define sibling identity and directly control state preservation, cleanup, and remount behavior.

A state setter changes the current variable.

It queues work for a future render; the current render and its closures keep their snapshot.

Server Components replace Client Components.

Server Components remove noninteractive code from the client graph; interactive state, Effects, and browser APIs still need Client Components.

Senior React interviews are production reasoning interviews

Start with evidence, identify the responsible layer, mitigate user harm, change one hypothesis, and verify the same workload. Hook vocabulary alone does not diagnose an incident.

Each scenario expands into a concise answer in the question library; the cornerstone incidents continue into investigation guides.

Scenario 01

One filter renders the whole dashboard

Collect evidence
Update owner, React render reasons, commit duration, context value identity, layout, and user-visible latency.
Make the decision
Move state to the correct owner, narrow notification scope, then memoize only a measured expensive boundary.
Rehearse this scenario

Scenario 02

Typing into search feels delayed

Collect evidence
Input event task, synchronous filtering, render path, requests, layout, paint, and third-party handlers.
Make the decision
Keep input urgent and local; defer, transition, cancel, or move only the proven blocking work.
Rehearse this scenario

Scenario 03

Memory grows after repeated navigation

Collect evidence
Heap retaining paths, detached DOM, subscriptions, timers, observers, caches, portals, and library instances.
Make the decision
Fix the retaining owner or capacity bound, then repeat the lifecycle until memory reaches a stable plateau.
Rehearse this scenario

Scenario 04

One Context updates the application

Collect evidence
Provider ownership, value identity, consumer set, update frequency, and selector needs.
Make the decision
Split cohesive responsibilities, narrow providers, and use slice subscriptions for high-frequency shared data.
Rehearse this scenario

Scenario 05

Fast display, slow interactivity

Collect evidence
Bundle transfer, parse/compile, module initialization, hydration, long tasks, third parties, and component work.
Make the decision
Remove or split client code, reduce hydration work, defer third parties, and verify interaction latency on real devices.
Rehearse this scenario

Scenario 06

Older search results overwrite newer ones

Collect evidence
Request start/completion order, active query key, cancellation, debounce, and cache writes.
Make the decision
Abort obsolete work and guard result commits; centralize shared remote-state policy in a data layer.
Rehearse this scenario

Scenario 07

50,000 rows freeze the browser

Collect evidence
Loaded records, mounted DOM, render/commit time, layout, memory, sorting, and scroll behavior.
Make the decision
Bound data with pagination and UI with virtualization while preserving focus and selection identity.
Rehearse this scenario

Scenario 08

A release introduces hydration mismatches

Collect evidence
Raw HTML, parsed DOM, first client inputs, locale, dates, random IDs, flags, extensions, CDN, and asset versions.
Make the decision
Restore deterministic first output and roll back if needed; never hide a broad mismatch with suppression.
Rehearse this scenario

Scenario 09

WebSocket updates outrun the UI

Collect evidence
Ingress rate, buffer depth, parse cost, snapshot age, render cadence, dropped updates, and user-visible lag.
Make the decision
Coalesce, sample, bound, publish snapshots deliberately, and expose freshness with a resync path.
Rehearse this scenario

Scenario 10

A component contains fourteen intertwined Effects

Collect evidence
External system per Effect, dependency graph, cascaded updates, derived state, event work, and cleanup ownership.
Make the decision
Remove non-Effects, model explicit transitions, and extract cohesive lifecycles without merging unrelated synchronization.
Rehearse this scenario

Staff+ answers scale change across teams

The unit of design is no longer one component. It is a platform boundary, migration path, capacity contract, contribution model, and reversible technical strategy.

Migrate 300 inconsistent components

Tokens, accessible primitives, versioning, codemods, adoption incentives, governance, and measurable product impact.

Open architecture question

Decide whether microfrontends fit

Organizational autonomy versus runtime integration, dependency, performance, UX, and observability cost.

Open architecture question

Define real-time frontend capacity

Ingress, coalescing, snapshot cadence, selector subscriptions, overload policy, freshness SLOs, and resync.

Open architecture question

Build a versioned form platform

Schema evolution, accessible rendering, validation, migrations, extensions, localization, and operational ownership.

Open architecture question

Go deeper without duplicating the repository

The React hub owns the interview mental model. Existing implementation guides and JavaScript mechanics remain the canonical deeper resources.

  • Typeahead controller

    Reuse the existing debounce, AbortController, cache, and stale-response mechanics instead of duplicating them here.

  • Infinite-scroll controller

    Study sentinel loading, in-flight guards, end-of-data behavior, retry, and the virtualization boundary.

  • Hydration mismatch field guide

    Use the dedicated production guide for dates, storage, invalid HTML, CDN mutations, and deployment-only mismatches.

  • Virtual tree diffing exercise

    Explore a framework-free tree diff without confusing the exercise with React's current internal implementation.

  • Existing React articles

    Browse the React 19, hooks, debounce, accordion, and TypeScript component articles already maintained in the repository.

  • System design library

    Connect frontend state and capacity decisions to APIs, reliability, data ownership, and distributed systems.

Search the React question library

Search questions, direct answers, tags, or runtime concepts. Reveal concise answers in place, then open cornerstone rendering and production topics as layered deep dives.

0 studied111 total
Next: What rendering does

Showing 111 of 111 questions

React Mental Model

Declarative UI, component execution, render snapshots, purity, one-way data flow, and render-versus-commit reasoning.

Interview focus: Predict behavior from a render snapshot before reaching for hook or DOM terminology.

  • FundamentalsRendering3 min

    Render cycle

    What actually happens when React renders a component?

    Build the core model: React calls components to calculate a tree description, then commits only necessary host changes.

    rendercomponentcommit
    30-second interview answer

    A render is React calling components to calculate the next UI description from props, state, and context. That calculation must stay pure and may be restarted. React then compares the next tree with the previous one, and during commit applies necessary host changes such as DOM mutations and refs. Browser layout and paint happen after React's work; component execution does not imply a DOM update.

    Open deep dive →
  • FundamentalsConcept3 min

    State snapshots

    What does it mean that React state is a snapshot?

    Explain why setting state schedules another render rather than mutating the variable already captured by the current render.

    statesnapshotevents
    30-second interview answer

    Each render receives fixed state values. Calling a setter queues work for a future render; it does not change the state variable inside the current event handler or closure. That is why several setCount(count + 1) calls from one render all calculate from the same count. Functional updates express a transition from the queued previous value when the next state depends on it.

    Open deep dive →
  • IntermediateConcept3 min

    Purity

    Why should React rendering remain pure and deterministic?

    Connect pure component calculations to retries, interruption, Strict Mode checks, and predictable composition.

    purityrenderstrict-mode
    30-second interview answer

    React needs to call rendering code whenever it must calculate UI, and modern rendering work may be repeated, paused, or abandoned before commit. A pure component returns the same JSX for the same inputs and does not mutate external state during render, so those behaviors remain safe. User-caused side effects belong in event handlers; render-caused synchronization with external systems belongs in Effects.

    Concise answer
  • IntermediateRendering3 min

    Render cycle

    What is the difference between React's render and commit phases?

    Separate calculating the next tree from applying observable host changes.

    rendercommitDOM
    30-second interview answer

    Render is the pure calculation phase: React calls components and determines the next tree. Commit is when React applies the resulting host changes, updates refs, and runs the appropriate effect lifecycle. A component can render without producing a DOM mutation, and work calculated during concurrent rendering can be discarded before commit. Browser layout and paint are separate stages after DOM changes.

    Concise answer
  • FundamentalsRendering3 min

    Render triggers

    What causes a React component to render?

    Identify initial rendering, local state, ancestor rendering, context changes, and subscribed external-store updates.

    statepropscontext
    30-second interview answer

    A component renders initially when its tree is mounted. Later it can render because its own state changed, an ancestor rendered it again, a consumed context value changed, or a subscribed external store notified it. A render does not mean the DOM changed. Memoization can skip some ancestor-driven renders, but a component's own state and consumed context still update it.

    Concise answer
  • IntermediateRendering3 min

    Render propagation

    Does a parent render always cause its children to render?

    Explain the default recursive render path and the conditions under which React can reuse prior work.

    parentchildrenmemo
    30-second interview answer

    By default, when a component renders, React evaluates the child elements it returns and renders that subtree. React can reuse work at explicit or compiler-created memo boundaries when relevant inputs are unchanged, and already-created children passed through composition may keep stable element identity. Treat this as performance behavior, not correctness: children must be pure and correct whenever React calls them.

    Concise answer
  • AdvancedRendering3 min

    Identity

    What does React mean by component identity?

    Connect state preservation to element type, position in the tree, and keys.

    identitystatekeys
    30-second interview answer

    React associates state with a component identity in the rendered tree, determined primarily by element type, position among siblings, and key. If that identity remains stable, React preserves state across renders. If the type or key changes, or the component moves to a different identity position, React treats it as a different instance, cleans up the old one, and initializes new state.

    Open deep dive →
  • FundamentalsConcept3 min

    React values

    What is the difference between a React element and a component?

    Distinguish the component code React calls from the immutable description that JSX creates.

    elementcomponentJSX
    30-second interview answer

    A component is a function or class React can call to calculate UI. A React element is the immutable description produced by JSX or createElement: it records a type, props, and key. Rendering a component returns elements; React uses those elements to construct and reconcile the tree. Elements are descriptions, not DOM nodes and not mounted component instances.

    Concise answer

JSX & Component Contracts

JSX, elements, props, children, composition, controlled APIs, conditional rendering, lists, and TypeScript contracts.

Interview focus: Design a small, semantic API with explicit ownership and accessible defaults.

  • FundamentalsConcept3 min

    JSX

    What is JSX, and what does it become at runtime?

    Explain JSX as syntax transformed into calls that create React element descriptions.

    JSXtransformelements
    30-second interview answer

    JSX is syntax for expressing a React element tree alongside JavaScript. A build transform converts it to calls in the JSX runtime that create element descriptions containing the type, props, and key. JSX is neither HTML nor a template string: JavaScript expressions run while the component renders, and React later interprets the resulting elements for the target renderer.

    Concise answer
  • FundamentalsConcept3 min

    Component inputs

    How do props and state differ in ownership?

    Frame props and state around who owns a value rather than whether one can change.

    propsstateownership
    30-second interview answer

    Props are inputs owned by the parent for that render; the child must treat them as read-only. State is memory owned by a component identity and updated through React. Both are snapshots and both can differ on the next render. The design question is ownership: keep one source of truth at the lowest boundary that coordinates every reader and writer.

    Concise answer
  • IntermediateComponent API3 min

    Composition

    Why is composition usually preferable to a component with dozens of configuration props?

    Evaluate flexible child composition against a prop matrix that creates invalid combinations.

    compositionchildrenAPI design
    30-second interview answer

    Composition lets callers supply meaningful UI pieces through children or named slots while the parent owns layout and behavior. A large boolean-and-variant prop matrix creates combinatorial states, unclear precedence, and a brittle abstraction. Good APIs keep invariants inside the component, expose a small stable contract, and use composition only where callers genuinely need structural freedom.

    Concise answer
  • IntermediateComponent API3 min

    Component APIs

    What is the difference between controlled and uncontrolled component APIs?

    Compare parent-owned value/onChange contracts with component- or DOM-owned state.

    controlleduncontrolledforms
    30-second interview answer

    A controlled component receives its current value and reports requested changes, so the parent owns the source of truth. An uncontrolled component owns its state internally, often initialized with a default value, and may expose a ref or final value. Controlled APIs coordinate validation and cross-field behavior; uncontrolled APIs reduce update coupling. A reusable component should not silently switch modes during its lifetime.

    Concise answer
  • AdvancedRendering3 min

    Conditional rendering

    How can conditional rendering unexpectedly preserve or reset state?

    Reason about the tree React sees rather than the visual branch labels in source code.

    conditional renderingidentitystate
    30-second interview answer

    React preserves state when the same component type occupies the same identity position, even if different source-code branches produced it. It resets state when the type or key at that position changes. To predict behavior, sketch the resulting element tree for each condition. Avoid defining component functions inside another component because that creates a new component type every render.

    Concise answer
  • IntermediateComponent API3 min

    TypeScript

    How should you design TypeScript types for React component props?

    Use types to encode valid component modes rather than documenting illegal prop combinations.

    TypeScriptpropsdiscriminated union
    30-second interview answer

    Type the smallest public contract and encode mutually exclusive modes with discriminated unions instead of optional-prop combinations. Use explicit event and ref element types, model children according to the actual composition contract, and make callback payloads domain-specific. React.FC is optional; plain functions often preserve clearer generics and do not imply a children prop you may not support.

    Concise answer

State & Events

State snapshots, queued updates, batching, functional updates, reducers, derived state, lifting, and state placement.

Interview focus: Identify the source of truth, event boundary, and exact transition before choosing storage.

  • IntermediateState Design3 min

    State ownership

    When should React state stay local, and when should it be lifted?

    Place state at the lowest owner that must coordinate all readers and writers.

    local statelifting stateownership
    30-second interview answer

    Keep state local when only one subtree needs it; locality reduces coupling and render reach. Lift it to the nearest common owner when multiple peers must coordinate one source of truth. Do not lift state preemptively into a page or global store. Ask who reads it, who writes it, whether it must survive navigation, and whether a URL, server cache, or form boundary owns it better.

    Concise answer
  • IntermediateState Design3 min

    State structure

    What is derived state, and why is duplicating it dangerous?

    Compute values from existing inputs during render unless independent historical state is required.

    derived statesource of trutheffects
    30-second interview answer

    Derived data can be calculated from current props or state, such as a filtered list or full name. Storing another copy creates two sources of truth and a synchronization problem—often an unnecessary Effect and extra render. Calculate cheap derived values during render; memoize only measured expensive work. Store a value separately only when it represents independent user intent or history.

    Concise answer
  • IntermediateRendering3 min

    State updates

    How does React batch state updates?

    Explain why multiple updates can produce one render and why value-form updates still read one snapshot.

    batchingstateevents
    30-second interview answer

    React queues state updates and normally processes them together before the next render, avoiding an intermediate render after every setter call. Batching changes render frequency, not snapshot semantics: three setCount(count + 1) calls from one handler still enqueue the same replacement value. Three functional updates, setCount(c => c + 1), compose against the queued value and produce three increments.

    Concise answer
  • FundamentalsHook3 min

    State updates

    When should you use a functional state update?

    Use an updater when the next value depends on the prior queued value.

    useStatefunctional updatequeue
    30-second interview answer

    Use setState(previous => next) when the next value depends on the previous value, especially for multiple updates in one event or callbacks that run later. React applies updater functions in queue order to the pending state. If the next value comes entirely from current event data or props, a direct replacement is often clearer.

    Concise answer
  • SeniorState Design3 min

    State architecture

    How do local UI, shared client, server, URL, form, and cache state differ?

    Separate state by authority, persistence, sharing, and freshness instead of forcing everything into one store.

    server stateURL stateform state
    30-second interview answer

    Local UI state belongs to a component interaction; shared client state coordinates client-owned behavior; server state is a cached view of remote authority with freshness rules; URL state is navigable and shareable; form state is an editable draft; cache state has eviction and invalidation semantics. Choosing one global store for all six hides different lifetimes and correctness rules behind one API.

    Concise answer
  • AdvancedState Design3 min

    Event boundaries

    How do you decide whether logic belongs in an event handler or an Effect?

    Place user-caused work in the interaction and render-caused external synchronization in an Effect.

    eventseffectsside effects
    30-second interview answer

    If work happens because the user performed a specific action—submit, purchase, send—run it in that event path. If a component being present or a reactive value changing requires synchronization with an external system, use an Effect. Moving event-specific work into an Effect loses the cause, can repeat on remount, and creates indirect state choreography.

    Concise answer

Hooks & Stateful Composition

useState, useReducer, useRef, useContext, useMemo, useCallback, custom hooks, and stale closures.

Interview focus: Explain lifetime, closure capture, identity, and the architectural cost of each hook—not its syntax.

  • FundamentalsHook3 min

    Hook rules

    Why must Hooks be called at the top level of components and custom Hooks?

    Keep hook calls in a stable structural order so React can associate hook state with the correct call site.

    hooksruleslint
    30-second interview answer

    React associates Hook state with the component and the order of Hook calls. Conditional, looped, or nested function calls can change that order between renders and attach state to the wrong call. Call Hooks unconditionally at the component or custom-Hook top level, and express conditional behavior inside the Hook or by splitting components. The official lint rules enforce more than naming style—they protect runtime correctness.

    Concise answer
  • IntermediateState Design3 min

    useReducer

    When does useReducer improve state design over useState?

    Prefer a reducer when named events coordinate multiple fields or make state transitions easier to test.

    useReduceruseStatestate machine
    30-second interview answer

    useState is simplest for independent values and direct replacements. useReducer helps when several fields change together, transitions have domain names, or invariants deserve one pure transition function. It centralizes update logic but does not make state global or automatically faster. If the reducer becomes a switch over trivial setters, it adds ceremony without a clearer model.

    Concise answer
  • IntermediateHook3 min

    useRef

    When should you use useRef instead of state?

    Use refs for mutable values whose changes should not drive rendering, or for imperative host access.

    useRefstateDOM
    30-second interview answer

    A ref is a stable mutable cell across renders. Updating ref.current does not schedule a render, so refs fit DOM nodes, timer IDs, external instances, and bookkeeping not used to calculate visible UI. State belongs to values whose changes must appear in rendering. Reading or writing refs during render generally breaks purity; use them from events, effects, or ref callbacks.

    Concise answer
  • AdvancedHook3 min

    useRef

    How should you reason about storing a previous value in a ref?

    Clarify when the ref is updated and which render can observe the prior committed value.

    useRefprevious valueeffect
    30-second interview answer

    A common pattern reads a ref during render and updates it in an Effect after commit, so the next render sees the last committed value. That timing is the behavior—not a special previous-value feature. If previous state is needed to calculate the next state, use a reducer or functional update instead. Avoid ref-based shadow state that bypasses React's rendering model.

    Concise answer
  • AdvancedRendering3 min

    Context

    How does Context propagation affect rendering?

    Explain why changing a provider value updates consuming components and why one broad value expands render reach.

    contextproviderrerender
    30-second interview answer

    When a provider's value changes by Object.is comparison, React updates consumers that read that context, regardless of an ancestor memo boundary. A newly created object value changes every provider render. Stabilizing identity can help, but the architectural fix is often splitting contexts by change frequency, narrowing provider placement, or moving rapidly changing data to a selector-capable external store.

    Concise answer
  • AdvancedPerformanceStable in React 19.23 min

    Memoization

    Would adding useMemo improve a frequently rendering component?

    Require evidence that a calculation is expensive and dependency reuse is frequent enough to repay memoization.

    useMemoprofilingdependencies
    30-second interview answer

    Not necessarily. useMemo caches a calculation result between renders when dependencies are unchanged; it does not stop the component from rendering. Measure the calculation and render path first. Memoization adds dependency comparisons, retained memory, and correctness risk from stale dependencies. With React Compiler enabled, automatic memoization further reduces the need for manual useMemo, which remains an optimization rather than semantic storage.

    Context: React Compiler 1.0 can automatically memoize calculations; manual useMemo remains available for precise control and non-compiler builds.

    Concise answer
  • AdvancedPerformanceStable in React 19.23 min

    Memoization

    When is useCallback useful, and when is it noise?

    Use stable function identity only when a measured consumer benefits or dependency semantics require it.

    useCallbackfunction identitymemo
    30-second interview answer

    useCallback caches a function identity, not its result and not the work inside it. It can help a memoized child avoid a prop change or stabilize a dependency, but wrapping every handler adds code and dependency risk without benefit when consumers render anyway. Prefer simpler code, profile the path, and account for React Compiler automatic memoization where enabled.

    Concise answer
  • SeniorArchitecture3 min

    Custom hooks

    What makes a custom Hook a good abstraction?

    Extract a coherent stateful capability with an honest contract, not merely repeated lines of code.

    custom hookabstractioncomposition
    30-second interview answer

    A good custom Hook owns one coherent stateful or synchronization concern, exposes a small domain contract, and leaves UI composition with components. It makes lifecycle, dependencies, and error behavior explicit. A Hook that mixes fetching, analytics, navigation, and form state hides ownership and becomes difficult to test. Reuse is a consequence; clarity of the boundary is the primary reason.

    Concise answer
  • AdvancedDebugging3 min

    Closures

    What is a stale closure in React, and why does it happen?

    Trace a callback back to the render whose values it captured.

    closuretimercallback
    30-second interview answer

    Every render creates functions that close over that render's props and state snapshot. If a timer, listener, promise callback, or memoized function runs later, it still sees those captured values unless it is recreated with correct dependencies or reads the latest value through an intentional pattern. Fix the ownership or dependency model; do not suppress the linter and hope the closure stays current.

    Open deep dive →

Effects & Synchronization

External synchronization, dependency correctness, cleanup, subscriptions, timers, request races, and effect removal.

Interview focus: Name the external system and independently prove setup, resynchronization, and cleanup.

  • FundamentalsHook3 min

    Effect model

    What is a React Effect?

    Define Effects as render-driven synchronization with systems outside React, not lifecycle callbacks for arbitrary code.

    useEffectsynchronizationexternal system
    30-second interview answer

    An Effect describes how a committed render synchronizes with an external system such as a subscription, browser API, timer, network connection, or third-party widget. React runs setup after commit, runs cleanup before resynchronizing with changed dependencies, and cleans up on unmount. If there is no external system, the code probably belongs in render or an event handler.

    Open deep dive →
  • IntermediateDebugging3 min

    Avoiding Effects

    Why is an Effect that copies firstName and lastName into fullName state unnecessary?

    Show how an Effect creates a stale intermediate render and duplicated state for a pure calculation.

    useEffectderived stateextra render
    30-second interview answer

    fullName is fully determined by current props, so calculate it during render. Storing it creates another source of truth: React first commits stale fullName, the Effect sets it, and React renders again. The dependency array only maintains the synchronization problem. Reserve state for independent information and Effects for external systems.

    Open deep dive →
  • AdvancedHook3 min

    Dependencies

    How should you reason about a useEffect dependency array?

    Treat dependencies as a description of values the synchronization process reads, not a scheduling preference.

    useEffectdependencieslint
    30-second interview answer

    Dependencies are every reactive value read by the Effect's setup. React compares them with Object.is to decide when that external synchronization must be torn down and recreated. You do not choose dependencies to control timing; change the code so the desired dependency model is truthful—move event work to events, derive values during render, split independent Effects, or stabilize genuine inputs.

    Concise answer
  • IntermediateHook3 min

    Cleanup

    When and why does an Effect cleanup function run?

    Model cleanup as undoing one setup before a new synchronization starts or the component leaves.

    cleanupsubscriptionunmount
    30-second interview answer

    Cleanup runs before React applies the Effect setup again with changed dependencies and when the component unmounts. In development Strict Mode, React also performs an extra setup-cleanup-setup cycle to expose missing teardown. Cleanup should symmetrically disconnect, unsubscribe, clear, or cancel what that setup created; it should not perform unrelated global reset work.

    Concise answer
  • AdvancedDebuggingStable in React 19.23 min

    Strict Mode

    Why can Effects appear to run twice in React Strict Mode?

    Explain the development-only setup/cleanup stress test and the bug it is designed to reveal.

    StrictModeuseEffectcleanup
    30-second interview answer

    In development, Strict Mode intentionally runs an extra Effect setup and cleanup cycle to reveal code that cannot safely disconnect and reconnect. Production does not keep that extra cycle. The fix is not a ref that suppresses setup; make cleanup undo setup and make the external operation safe for remounting. Duplicate irreversible user actions usually belonged in an event handler.

    Context: This is a development-only Strict Mode behavior; production setup follows the committed lifecycle.

    Concise answer
  • SeniorDebugging3 min

    Async effects

    How do request race conditions happen in an Effect, and how do you prevent stale results?

    Handle Alice-then-Bob request ordering with cancellation and a stale-result guard, or move fetching to a data layer.

    fetchAbortControllerrace condition
    30-second interview answer

    Effects can start request A, then request B after input changes; if A finishes last, it can overwrite B's newer result. Cleanup should abort obsolete work where supported, and the completion path must ignore results that no longer match the active request. In production, prefer a framework loader or query/cache layer that also handles deduplication, freshness, retries, and navigation races.

    Open deep dive →
  • SeniorArchitecture3 min

    Effect architecture

    Why are chains of Effects that update state an architectural smell?

    Replace effect-driven state choreography with direct calculations or one explicit event transition.

    useEffectstate machinerender chain
    30-second interview answer

    A chain where Effect A sets state for Effect B creates indirect control flow, extra commits, fragile dependencies, and intermediate states the user can observe. If the values are derivable, calculate them in render. If one user or server event causes a multi-field transition, update it together—often through a reducer. Keep separate Effects only for genuinely independent external synchronization processes.

    Concise answer

Rendering & Reconciliation

Tree identity, keys, state preservation, parent renders, memo boundaries, reconciliation, commits, and DOM updates.

Interview focus: Separate component execution from host mutation and reason about identity by type, position, and key.

  • IntermediateRendering3 min

    Reconciliation

    What problem does React reconciliation solve?

    Explain how React relates two render results to preserve identity and compute necessary host work.

    reconciliationtreeidentity
    30-second interview answer

    Reconciliation relates the previous and next React trees so React can decide which component identities and host nodes to reuse, update, insert, or remove. Type, position, and keys guide that relationship. It is broader than a DOM diff: reconciliation also determines component lifetime and state preservation. The commit phase later applies the resulting host changes.

    Concise answer
  • IntermediateRendering3 min

    Keys

    Why are keys necessary, and how do they affect state preservation?

    Treat a key as part of sibling identity, not as a warning-suppression attribute.

    keyslistsstate
    30-second interview answer

    Keys tell React which sibling in the next list corresponds to which sibling in the previous list. A stable domain key lets state and DOM association follow an item through insertion, removal, and reordering. Keys need only be unique among siblings, but they must be stable across renders. Generating a new key during render makes every item appear new and resets state.

    Open deep dive →
  • IntermediateDebugging3 min

    Keys

    Why is an array index often a poor React key?

    Show how position-based identity attaches state to the wrong logical item when a list changes order.

    keysarray indexreorder
    30-second interview answer

    An index identifies a position, not the domain item occupying it. If items are inserted, removed, filtered, or reordered, React can reuse a component and its local state for a different item, causing wrong input values, focus, or animation state. An index is acceptable for a truly static list with no reordering and no item identity; a stable data ID is the normal choice.

    Concise answer
  • IntermediateRendering3 min

    Keys

    What happens when a component's key changes?

    Explain deliberate and accidental remounting through a changed identity.

    keyremountcleanup
    30-second interview answer

    A changed key gives the element a new identity. React unmounts the previous component, runs its cleanup, discards its state, mounts a new instance, and creates the necessary host work. This can deliberately reset a form for a new entity, but using unstable keys causes lost input, repeated subscriptions, broken focus, and unnecessary DOM work.

    Concise answer
  • AdvancedRendering3 min

    State preservation

    Why can moving a component in the tree reset its state?

    State belongs to React's identity position rather than to a JSX tag in source code.

    statetree positionidentity
    30-second interview answer

    State is stored by React for an identity position in the rendered tree. Moving the same-looking JSX to a different parent or sibling identity can remove the old component and create a new one, so state resets. If state must follow a domain entity, preserve its stable keyed position or move the state to an owner whose lifetime matches the entity.

    Concise answer
  • AdvancedRendering3 min

    Commit behavior

    How is reconciliation different from DOM updating?

    A component tree can be recalculated while React reuses every existing DOM node.

    reconciliationDOMcommit
    30-second interview answer

    Reconciliation is React's process for relating previous and next element trees, including component identity and state lifetime. DOM updating is only the host mutation work selected from that process and applied during commit. A parent and many children may render, yet if their host output is unchanged React may perform no DOM mutations. The browser separately handles style, layout, paint, and compositing.

    Concise answer
  • AdvancedDebugging3 min

    Component identity

    Why should you avoid defining a component inside another component?

    A new component function object on each parent render creates a different element type.

    component typeidentitystate reset
    30-second interview answer

    Defining a component inside another component creates a new function object each parent render. React sees a different element type at that position, so it remounts the subtree, resets state, and repeats setup and cleanup. Define component types at module scope and pass changing data through props. An inline callback or render function is different—it is a value, not necessarily an element type.

    Concise answer
  • AdvancedPerformanceStable in React 19.23 min

    Memoization

    What does React.memo skip, and what can still make a memoized component render?

    Memo can skip an ancestor-driven render with equal props, but it is neither a semantic guarantee nor a universal shield.

    React.memopropscontext
    30-second interview answer

    React.memo can reuse a component's previous result when its parent renders and props compare equal by Object.is. The component still renders for its own state updates and consumed context changes, and React may render it for other reasons because memoization is an optimization. New object or function props defeat shallow equality. React Compiler can supply equivalent optimization automatically when enabled.

    Concise answer

React Performance Engineering

Profiler evidence, render cost, memoization, context propagation, virtualization, bundles, long tasks, and browser work.

Interview focus: Observe, profile, locate the limiting work, change one hypothesis, and verify the user-facing result.

  • IntermediatePerformance3 min

    Performance model

    Is React re-rendering inherently expensive?

    Distinguish cheap component calculations from expensive work inside them and from host/browser costs.

    rerendercostprofiling
    30-second interview answer

    A re-render is work, but it is not automatically a performance problem. Many component calculations are cheap and produce no DOM changes. Cost comes from tree size, expensive calculations, unstable dependencies, broad context or state updates, host mutations, layout, paint, and synchronous third-party work. Measure interaction latency and profiles before trading simplicity for memoization.

    Concise answer
  • SeniorDebugging3 min

    Profiling

    How do you investigate a slow React interaction before optimizing it?

    Start from a repeatable user symptom, correlate React and browser traces, then verify one targeted change.

    ProfilerPerformance panelmeasurement
    30-second interview answer

    Reproduce the exact interaction with production-like data and record a browser Performance trace plus React DevTools profile. Determine whether time is in JavaScript, React rendering, a commit, layout/paint, network, or third-party work. Identify why the expensive subtree rendered, form one hypothesis, make the smallest architectural or algorithmic change, and remeasure the user-visible latency and regressions.

    Open deep dive →
  • AdvancedPerformance3 min

    Profiling

    What should you look for in the React DevTools Profiler?

    Use commit timing and render reasons to find unexpectedly broad or expensive component work.

    React DevToolsProfilercommit
    30-second interview answer

    Inspect which commits correspond to the slow interaction, their duration, which components rendered, and why inputs changed. Look for a broad subtree updated by high state or context, an individually expensive calculation, repeated commits caused by Effects, or unstable props defeating a bailout. Correlate with the browser trace because React profiles do not explain network waits, layout, paint, or third-party scripts alone.

    Concise answer
  • AdvancedState Design3 min

    State locality

    How does state locality affect React performance?

    State placed high in the tree expands the default render path even when only a leaf needs the value.

    state localityrender reachownership
    30-second interview answer

    An update renders the owning component and, by default, its subtree. Moving ephemeral state closer to the components that need it reduces render reach and coupling without memoization. Before optimizing props, ask whether hover, draft input, dialog state, or selection was lifted too high. Shared state should still live at the lowest boundary that genuinely coordinates all consumers.

    Concise answer
  • SeniorDebugging3 min

    Context performance

    How do you diagnose and reduce Context-induced rendering?

    Measure consumers, update frequency, and provider identity before splitting or replacing the architecture.

    contextproviderProfiler
    30-second interview answer

    Profile which consumers update and inspect whether the provider recreates a composite object on unrelated changes. Stabilize genuine provider values, split contexts by responsibility and change frequency, narrow provider placement, and separate state from dispatch where useful. For high-frequency or large shared data, a selector-based external store can notify only affected readers. Do not memo every consumer before fixing the ownership boundary.

    Concise answer
  • SeniorSystem Design3 min

    Virtualization

    How would you render 100,000 rows without freezing the browser?

    Render a bounded window of visible rows rather than optimizing 100,000 mounted components.

    virtualizationDOM sizewindowing
    30-second interview answer

    Use windowing: render only visible rows plus a small overscan buffer, represent total height with spacers, and recycle positions as the viewport moves. Define stable item identity, row measurement for variable heights, keyboard and screen-reader behavior, focus retention, and scroll restoration. Pagination bounds data transfer; virtualization bounds DOM and render work. React.memo alone leaves the huge DOM mounted.

    Open deep dive →
  • AdvancedPerformance3 min

    Bundles

    How should React applications approach code splitting and lazy loading?

    Split around meaningful user journeys, then prevent the new boundaries from creating request waterfalls.

    lazySuspensebundle
    30-second interview answer

    Split code at route or feature boundaries that materially reduce initial JavaScript, not every small component. Provide a stable loading experience, preload likely next paths, and track chunk size, cacheability, and failed dynamic imports. Excessive splitting adds request and Suspense coordination overhead. Measure parse, compile, execution, and interaction readiness—not only compressed bundle bytes.

    Concise answer
  • SeniorDebugging3 min

    Browser performance

    How do you distinguish React rendering cost from browser layout and paint cost?

    Use React profiles for component work and browser traces for scripting, style, layout, paint, and compositing.

    layoutpaintlong task
    30-second interview answer

    React DevTools shows component render and commit work. The browser Performance panel shows the full main-thread task, including JavaScript outside React, style recalculation, forced layout, paint, and compositing. If a small commit triggers expensive layout on a massive DOM, memoization misses the bottleneck. Correlate timestamps and test whether the limit is component work, DOM size, CSS/layout, or network.

    Concise answer

Modern React Architecture

React 19.2, transitions, Suspense, Compiler, SSR, hydration, streaming, Server Components, and framework boundaries.

Interview focus: Distinguish stable React APIs from framework integration and unstable implementation interfaces.

  • AdvancedRenderingStable in React 19.23 min

    Concurrent rendering

    What does concurrent rendering mean in React, and is it parallel rendering?

    Describe interruptible and prioritized rendering without claiming components execute in parallel threads.

    concurrencypriorityinterruptible render
    30-second interview answer

    Concurrent rendering lets React prepare multiple versions of UI with priority-aware, interruptible render work. A lower-priority render can pause or restart so an urgent input update stays responsive; only a completed consistent tree commits. It does not mean component functions run simultaneously on multiple JavaScript threads. Purity is what makes restartable calculation safe.

    Open deep dive →
  • AdvancedPerformanceStable in React 19.23 min

    Transitions

    When does useTransition improve responsiveness?

    Mark a non-urgent state transition so urgent input can update while React prepares expensive UI.

    useTransitionprioritypending UI
    30-second interview answer

    useTransition marks selected state updates as non-blocking. React can interrupt that render to process urgent work such as typing, while isPending supports intentional pending feedback. It does not make expensive JavaScript faster and should not control a text input's own value. Use it when rendering the destination is costly and keeping the current interface responsive is better than blocking.

    Concise answer
  • AdvancedPerformanceStable in React 19.23 min

    Transitions

    How is useDeferredValue different from debouncing?

    Defer rendering a value without introducing a fixed timer or automatically reducing network traffic.

    useDeferredValuedebouncerendering
    30-second interview answer

    useDeferredValue lets an urgent render use the old value while React prepares a lower-priority render with the new one. It has no fixed delay and does not prevent requests from firing. Debouncing waits for input to settle before invoking work and can reduce calls. Choose based on whether the bottleneck is render responsiveness, request volume, or both.

    Concise answer
  • AdvancedArchitectureStable in React 19.23 min

    Suspense

    What problem does Suspense solve, and what does it not do by itself?

    Coordinate loading and reveal behavior for compatible resources without treating Suspense as a generic fetching client.

    Suspensefallbackstreaming
    30-second interview answer

    A Suspense boundary defines where React may show fallback UI while a compatible child is not ready, and coordinates reveal during client rendering or streaming SSR. It does not fetch data, choose cache semantics, or make an arbitrary useEffect request suspend. The framework or data source must integrate with Suspense. Place boundaries around coherent user experiences to avoid flashing the whole page.

    Concise answer
  • SeniorPerformanceStable in React 19.23 min

    React Compiler

    How does React Compiler change the memoization discussion?

    Treat the compiler as stable build-time optimization, while preserving profiling, correctness, and measured rollout.

    React Compilermemoizationlint
    30-second interview answer

    React Compiler 1.0 is a stable build-time optimizer that analyzes component and Hook code and applies granular memoization automatically. It reduces routine useMemo, useCallback, and React.memo work, but it does not fix expensive algorithms, huge DOMs, network waterfalls, or broken state ownership. Adopt it incrementally, respect the Rules of React, test behavior, and verify performance rather than assuming every component improves.

    Context: React Compiler 1.0 became stable in October 2025 and supports incremental adoption; integrations remain build-tool specific.

    Open deep dive →
  • SeniorArchitectureFramework-dependent3 min

    Server Components

    What are React Server Components, and where is the client boundary?

    Separate React's stable Server Component model from framework implementations and interactive client code.

    Server Componentsclient boundaryserialization
    30-second interview answer

    Server Components render ahead of the client bundle in a separate environment, can access server-side data, and send rendered output rather than their component code to the browser. Interactive state, Effects, and browser APIs belong in Client Components. Values crossing the boundary must be serializable by the integration. React 19 stabilizes the component model, while bundler/framework implementation APIs can still change between minors.

    Context: Server Components are stable in React 19; production routing, caching, server functions, and bundling are supplied by a framework, whose underlying RSC APIs require careful version alignment.

    Open deep dive →
  • Staff / PrincipalArchitectureFramework-dependent3 min

    Server Components

    When would moving a component to the server actually improve an application?

    Evaluate bundle removal and data locality against interaction, serialization, caching, and network boundaries.

    server boundarybundle sizedata locality
    30-second interview answer

    A server boundary helps when rendering needs server-only data or heavy noninteractive libraries, and the output can cross as serializable UI without shipping that code to the client. It is less useful for highly interactive, offline, or rapidly client-updated behavior. Measure client JavaScript, waterfall removal, cache behavior, navigation latency, and server cost. A Server Component is not automatically a security boundary for data passed to clients.

    Concise answer
  • SeniorArchitectureFramework-dependent3 min

    Server rendering

    How do SSR and Server Components differ?

    SSR produces initial HTML; Server Components change which component code and data work belong in the client graph.

    SSRServer Componentshydration
    30-second interview answer

    SSR renders a React tree to HTML for the initial response; interactive client components still load JavaScript and hydrate. Server Components define components that do not enter the client bundle and whose rendered result can compose with Client Components. Frameworks often combine RSC, SSR, streaming, and routing, but they solve different problems: initial HTML delivery versus the server/client component graph.

    Concise answer
  • SeniorDebugging3 min

    Hydration

    What is hydration, and what causes hydration mismatches?

    Hydration attaches React to server-rendered HTML and requires the first client output to match.

    hydrationSSRmismatch
    30-second interview answer

    Hydration lets React attach behavior to server-rendered HTML while reusing that DOM. The first browser render must match the server output in structure, text, attributes, and stable IDs. Dates, locale, random values, browser-only storage, invalid HTML, request-specific data, extensions, and CDN rewrites can diverge. Find and remove the nondeterministic source; suppression is only a narrow escape hatch.

    Open deep dive →
  • SeniorArchitectureFramework-dependent3 min

    Server rendering

    How do streaming SSR and Suspense change server-rendered delivery?

    Send an initial shell and reveal completed Suspense regions without waiting for the slowest data dependency.

    streamingSSRSuspense
    30-second interview answer

    Streaming SSR can send the ready application shell first, then stream later Suspense boundary output as dependencies resolve. This improves progressive delivery but introduces boundary placement, fallback stability, error recovery, caching, abort, and hydration coordination decisions. It does not remove server latency or client JavaScript cost. Frameworks determine the data, routing, and deployment integration around React's server APIs.

    Concise answer
  • AdvancedHookStable in React 19.23 min

    Effect Events

    What problem does useEffectEvent solve in React 19.2?

    Extract non-reactive event-like logic from an Effect while still reading the latest props and state.

    useEffectEventuseEffectclosure
    30-second interview answer

    useEffectEvent lets an Effect call non-reactive logic that always sees current props and state without making those values dependencies of the synchronization process. It is useful when connection setup depends on roomId but a notification should use the latest theme. It is not a general dependency escape hatch, cannot be passed around arbitrarily, and does not replace normal user event handlers.

    Context: useEffectEvent became stable in React 19.2.

    Concise answer

Data, Caching & Forms

Fetching placement, caches, stale data, optimistic work, controlled/uncontrolled inputs, validation, and large forms.

Interview focus: Design ownership, freshness, cancellation, failure recovery, and field-level update boundaries together.

  • SeniorArchitecture3 min

    Data fetching

    When should data fetching not live in a component Effect?

    Prefer server/framework loaders or a query cache when fetching is part of route data rather than ad hoc synchronization.

    data fetchingframework loadercache
    30-second interview answer

    Fetching in an Effect starts after render, repeats boilerplate for loading and races, and can create parent-child waterfalls. Route data often belongs in a framework loader or server boundary; shared client data often belongs in a query/cache layer with deduplication, freshness, cancellation, and invalidation. An Effect remains reasonable for small client-only synchronization where the component truly owns the request lifetime.

    Concise answer
  • AdvancedState Design3 min

    Data architecture

    How is server state different from client state?

    Server state is a cached remote view with freshness and ownership constraints, not simply another global object.

    server statecacheclient state
    30-second interview answer

    Client state is authoritative inside the client for interactions such as a draft or open panel. Server state is a local snapshot of remote authority: it can become stale, be refetched, invalidated, shared, or conflict with mutations from elsewhere. A query cache models those semantics better than manually copying responses into a generic global store. Optimistic UI is a temporary client projection, not a transfer of authority.

    Concise answer
  • SeniorState DesignStable in React 19.23 min

    Mutations

    How do you design optimistic updates without hiding failure?

    Update perceived state immediately while preserving pending status, rollback/reconciliation, and duplicate-submission safety.

    optimistic UIrollbackconflict
    30-second interview answer

    Apply an optimistic projection only when success is likely and the rollback or correction is understandable. Give the mutation a stable identity, show pending status, prevent accidental duplicates, and reconcile with the authoritative response. On failure, restore or mark the item and offer recovery. For conflicting collaborative data, define merge/version rules instead of assuming last response wins.

    Concise answer
  • IntermediateState Design3 min

    Forms

    When should a form input be controlled or uncontrolled?

    Choose based on who needs each keystroke and how broadly the draft must coordinate.

    formscontrolleduncontrolled
    30-second interview answer

    A controlled input mirrors its value in React state and is useful when rendering, validation, or other fields depend on each change. An uncontrolled input lets the DOM hold the live value and reads it at a boundary such as submit, reducing render coupling. Both can be accessible and validated. Large forms often combine uncontrolled field storage or field subscriptions with React-owned form-level status.

    Concise answer
  • SeniorSystem Design3 min

    Large forms

    How would you redesign a slow 200-field React form?

    Bound keystroke work with field-level ownership or subscriptions before adding memoization.

    formsperformancevalidation
    30-second interview answer

    Profile one keystroke, then stop routing every field change through one form component. Give fields local or uncontrolled draft storage, subscribe only affected fields and summaries, and run expensive validation at deliberate boundaries or in incremental slices. Preserve accessible labels, error association, focus-to-error, server validation, and draft recovery. Virtualize only if hidden field DOM itself is large and navigation semantics remain intact.

    Concise answer
  • Staff / PrincipalArchitecture3 min

    Caching

    What should a React data cache decide beyond storing responses?

    Define keys, freshness, invalidation, retry safety, ownership, and capacity as part of the data contract.

    cacheretryinvalidation
    30-second interview answer

    A cache needs stable query identity, freshness windows, deduplication, cancellation, invalidation after mutation, garbage collection, persistence rules, and authorization-aware scoping. Retries need bounded backoff and method safety; they must not amplify a failing dependency. Decide whether stale data can remain visible, how offline or partial failure appears, and how telemetry distinguishes cache hit, revalidation, and network failure.

    Concise answer

Testing & Accessibility

Behavior-first tests, async assertions, mocking boundaries, keyboard interaction, focus, semantics, ARIA, and live regions.

Interview focus: Protect user-observable behavior across input modes rather than component implementation details.

  • IntermediateTesting3 min

    Component testing

    What should a React component test actually verify?

    Test behavior a user or consuming component can observe, not internal state or hook calls.

    Testing Librarybehavioruser
    30-second interview answer

    A component test should exercise the public behavior: render accessible output, perform realistic user interactions, and assert the resulting UI, callback, or navigation. Query by role and label where possible because that resembles how users and assistive technology find controls. Avoid asserting private state, exact component trees, or how many times a Hook ran unless that is itself an external contract.

    Concise answer
  • AdvancedTesting3 min

    Testing strategy

    How do unit, component, integration, and end-to-end tests fit a React application?

    Place tests at the cheapest boundary that proves the risk, with integration tests carrying most user-flow confidence.

    unitintegrationE2E
    30-second interview answer

    Unit-test pure domain transitions and utilities; component/integration tests cover rendered behavior across components, state, and mocked network boundaries; E2E tests protect a small set of critical journeys in the deployed stack. The goal is risk coverage, not a fixed ratio. Too many isolated component mocks miss integration failures, while too many broad E2E tests become slow and hard to diagnose.

    Concise answer
  • AdvancedTesting3 min

    Test doubles

    What should you mock in React tests?

    Mock slow or nondeterministic external boundaries while keeping meaningful application collaboration real.

    mockingnetworkdependency
    30-second interview answer

    Mock the network, clock, browser capability, or external service boundary when control and determinism matter. Prefer request-level mocks over mocking the data Hook implementation so caching, loading, and error UI still run. Do not mock every child component—the test then verifies wiring rather than behavior. Keep mock responses contract-shaped and include latency, empty, error, and cancellation cases.

    Concise answer
  • AdvancedTesting3 min

    Async testing

    How do you prevent flaky async React tests?

    Wait for observable outcomes and control external time or I/O rather than inserting arbitrary sleeps.

    asyncflaky teststimers
    30-second interview answer

    Trigger the user action, await the resulting accessible UI state, and let the test utility flush React work through its supported APIs. Control network responses and timers explicitly. Avoid fixed sleeps, un-awaited user events, shared mutable fixtures, and assertions that race intermediate loading states. A flaky test often reveals an application race or missing ownership boundary, so diagnose it rather than only increasing timeout.

    Concise answer
  • FundamentalsAccessibility3 min

    Accessibility

    What does accessibility-first React implementation start with?

    Start with native semantic elements, correct names, keyboard behavior, and visible focus before adding ARIA.

    semantic HTMLkeyboardlabels
    30-second interview answer

    Choose the native element that already carries the required semantics and keyboard behavior: button, link, input, heading, list. Give controls programmatic labels, preserve visible focus, expose validation and status, and test with keyboard and a screen reader. ARIA can describe a custom widget but does not add behavior; a div with role=button still requires keyboard activation and focus management.

    Concise answer
  • AdvancedAccessibility3 min

    Focus management

    How would you design an accessible modal component?

    Combine dialog semantics with focus entry, containment, dismissal, restoration, and background isolation.

    dialogfocuskeyboard
    30-second interview answer

    Use a real dialog pattern with an accessible name. On open, move focus to a meaningful element; keep Tab navigation inside while modal; support Escape and an explicit close control; prevent background interaction; then restore focus to the trigger when safe. Handle nested portals, scroll lock, destructive confirmation, and route changes. Prefer a proven accessible primitive because focus edge cases are extensive.

    Concise answer
  • SeniorAccessibility3 min

    Composite widgets

    How would you design an accessible autocomplete?

    Design input, popup, keyboard navigation, result status, selection, and async behavior as one interaction contract.

    comboboxARIAkeyboard
    30-second interview answer

    Use the ARIA combobox pattern with a labelled input, controlled popup state, listbox relationship, active option indication, and documented Arrow, Enter, Escape, and Tab behavior. Keep DOM focus predictable, announce result count/loading changes without noise, preserve typed text, and expose errors. Add debounce, cancellation, stale-result guards, caching, and mobile/touch behavior without breaking keyboard semantics.

    Open deep dive →

Component & Application Architecture

Headless and compound components, custom hooks, context boundaries, external state, domain APIs, and dependency inversion.

Interview focus: Keep change local, make invalid states difficult, and avoid abstractions that hide ownership.

  • SeniorArchitecture3 min

    State architecture

    How do Context and an external state-management library differ?

    Context distributes a value through a tree; a state library may add ownership, selectors, tooling, and update semantics.

    Contextexternal storeselectors
    30-second interview answer

    Context solves value distribution without prop drilling; it does not define state transitions, caching, selectors, persistence, or server synchronization. A reducer plus Context can be enough for modest low-frequency client state. An external store becomes useful when independent subscriptions, selector-based updates, middleware, time-travel/debugging, cross-root ownership, or established team conventions justify the added dependency.

    Concise answer
  • SeniorScenario3 min

    Context architecture

    What goes wrong when one Context holds auth, theme, notifications, preferences, and dashboard state?

    A single provider couples unrelated lifetimes, update frequencies, tests, and failure domains.

    contextcouplingrerender
    30-second interview answer

    Any changed composite value can update every consumer, and unrelated responsibilities become one dependency and test fixture. Split contexts by cohesive ownership and change rate, narrow provider placement, keep auth authority separate from presentation preferences, and move high-frequency dashboard data to a selector-capable store. The goal is clearer boundaries first and reduced render reach second.

    Concise answer
  • SeniorArchitecture3 min

    External state

    When is Redux useful in a modern React application?

    Use Redux when complex shared client state benefits from explicit transitions, selectors, middleware, and debugging—not by default.

    Reduxglobal stateselectors
    30-second interview answer

    Redux fits substantial shared client state with many writers, complex transitions, normalized entities, cross-feature coordination, or strong debugging and middleware needs. Redux Toolkit removes much boilerplate. It should not absorb every local input or replace a server-data cache. Compare it with Context plus reducer, an external store, URL state, and the team's operational needs before adding global ownership.

    Concise answer
  • AdvancedComponent API3 min

    Component APIs

    When is the compound component pattern useful?

    Expose semantic subcomponents that coordinate through a private owner without a giant configuration object.

    compound componentcontextcomposition
    30-second interview answer

    Compound components work when a control has recognizable parts—Tabs, List, Trigger, Panel—that need shared state but flexible composition. A private context can coordinate IDs, selection, and keyboard behavior while the public API remains declarative. Keep allowed structure and accessibility invariants clear. For a simple component, named props or children are often easier than an entire compound vocabulary.

    Concise answer
  • SeniorComponent API3 min

    Component APIs

    How would you design a reusable modal API?

    Separate open-state ownership, accessible dialog behavior, content composition, and application-level stacking.

    modalcontrolled APIportal
    30-second interview answer

    Offer controlled open/onOpenChange plus an optional uncontrolled default, semantic Trigger/Content/Title/Description/Close parts, and a portal/layer manager. The primitive owns focus, Escape, outside interaction, scroll locking, labelling, and restoration. Product code owns business actions and copy. Define nested-dialog and route-change behavior; avoid an imperative global openModal payload that erases type and ownership boundaries.

    Concise answer
  • Staff / PrincipalArchitecture3 min

    API design

    When does a reusable React component become too configurable?

    A component is too generic when its prop combinations encode several unrelated products and invalid states.

    API designvariantscomposition
    30-second interview answer

    Warning signs include boolean prop matrices, callbacks for every internal step, styling escape hatches that bypass invariants, and branches for unrelated domains. Split stable primitives from domain components, encode valid variants, and use composition at deliberate seams. Reuse should reduce coordinated change; if every caller needs exceptions, the abstraction has grouped code by visual similarity rather than shared behavior.

    Concise answer
  • Staff / PrincipalArchitecture3 min

    Application boundaries

    How does dependency inversion improve React component architecture?

    Keep UI dependent on small domain contracts rather than importing transport, storage, analytics, and framework details everywhere.

    dependency inversionportstesting
    30-second interview answer

    Define a domain-facing contract for operations and state, then provide adapters for HTTP, local storage, analytics, or framework navigation at a boundary. Components consume the contract through props, context, or a focused Hook. This keeps tests behavioral, migrations local, and server/client differences explicit. Do not introduce an interface for every function; invert volatile infrastructure dependencies that cross many features.

    Concise answer
  • AdvancedComponent API3 min

    TypeScript

    How do you type a reusable generic React component without losing inference?

    Let data infer the item type and require only the operations the component actually needs.

    TypeScriptgenericsinference
    30-second interview answer

    Declare the component as a generic function, infer T from items, and type callbacks such as getKey(item: T) and renderItem(item: T). Constrain T only when the component relies on a property; otherwise a required accessor keeps the component flexible. Polymorphic as props require careful ref and intrinsic-prop merging and are often unnecessary for domain components.

    Concise answer
  • AdvancedState Design3 min

    TypeScript

    How do discriminated unions improve reducer correctness?

    Give each event a literal type and exact payload, then enforce exhaustive transitions.

    TypeScriptreducerdiscriminated union
    30-second interview answer

    Model actions as a discriminated union so each event carries only its valid payload and the reducer narrows automatically. An exhaustive never check makes adding an event without handling it a compile error. Pair that with a state union when loading, success, empty, and error are mutually exclusive. Types cannot prove runtime server data, so validate external inputs at the boundary.

    Concise answer

React Frontend System Design

Autocomplete, virtualized data, real-time UI, notifications, modals, chat, and form-builder platforms.

Interview focus: Cover state, APIs, capacity, accessibility, failure, tests, and observability—not just component names.

  • SeniorSystem Design3 min

    Autocomplete

    How would you design a production autocomplete in React?

    Combine an accessible combobox state machine with bounded remote requests, stale-result protection, and observability.

    autocompletedebounceaccessibility
    30-second interview answer

    Separate input text, selected value, popup navigation, and remote query state. Debounce request start, abort obsolete work, guard response order, cache by normalized query, cap results, and define empty/error/offline UI. Implement combobox keyboard and screen-reader behavior, preserve focus, and measure input latency, request rate, cache hits, selection success, and errors. React is only one layer of this system.

    Concise answer
  • SeniorSystem Design3 min

    Large lists

    How do infinite scrolling and virtualization solve different problems?

    Infinite loading bounds data transfer per request; virtualization bounds mounted UI work.

    infinite scrollvirtualizationpagination
    30-second interview answer

    Infinite scroll loads more data as a sentinel approaches the viewport but can still accumulate thousands of DOM nodes. Virtualization renders only a window regardless of loaded item count. Large feeds often need both, plus cursor pagination, in-flight and end guards, error retry, focus and screen-reader strategy, deep linking, scroll restoration, and an alternative path when endless scrolling harms navigation.

    Concise answer
  • Staff / PrincipalSystem Design3 min

    Large lists

    How would you design a large virtualized data table?

    Design bounded row/column rendering alongside server queries, keyboard navigation, and reliable selection identity.

    tablevirtualizationsorting
    30-second interview answer

    Define a column schema and stable row IDs; push large sort/filter/page operations to an API; window visible rows and possibly columns with measured sizes and overscan. Keep selection independent of mounted rows, preserve keyboard navigation and focus as cells recycle, expose table semantics or an accessible grid pattern, and handle resize, sticky regions, loading gaps, export, and scroll restoration. Profile DOM, memory, and interaction latency.

    Concise answer
  • Staff / PrincipalSystem Design3 min

    Real-time UI

    How would you design a React dashboard receiving 100 updates per second?

    Decouple transport rate from human-visible render rate and make overload behavior explicit.

    WebSocketbatchingbackpressure
    30-second interview answer

    Do not call setState for every message. Parse and normalize updates outside broad component state, coalesce by entity, and publish snapshots at an intentional cadence such as animation frames or a lower sampling rate. Use selector subscriptions so only affected widgets update. Bound buffers, drop or aggregate obsolete telemetry, resync after gaps, and expose connection lag. Capacity is messages in, processing cost, retained history, and renders out.

    Concise answer
  • SeniorSystem Design3 min

    Real-time UI

    What should a React chat-interface design cover beyond rendering messages?

    Model optimistic send state, acknowledgements, ordering, pagination, reconnection, and scroll behavior.

    chatoptimistic UIWebSocket
    30-second interview answer

    Give every outgoing message a client ID and pending/failed/sent state, reconcile it with server identity, and define ordering under reconnect or clock skew. Page older history without breaking the scroll anchor, virtualize long conversations, coalesce presence/typing updates, and preserve draft state. Include retry idempotency, attachment progress, offline behavior, accessibility announcements, abuse controls, and telemetry for delivery lag and failure.

    Concise answer
  • SeniorSystem Design3 min

    Notifications

    How would you design an application notification system?

    Separate durable notifications from transient feedback and define queueing, deduplication, accessibility, and recovery.

    notificationstoastlive region
    30-second interview answer

    Model durable inbox items separately from transient toasts. Give events IDs, priority, deduplication, expiry, and actions; bound the visible toast queue; pause dismissal for interaction; and use an appropriate live region without announcing a burst of low-value updates. Keep success feedback near the triggering control when possible. Persist read state server-side if it must cross devices and measure delivery and action outcomes.

    Concise answer
  • Staff / PrincipalSystem Design3 min

    Platform design

    How would you design a React form-builder platform?

    Treat forms as versioned domain schemas with an editor, renderer, validation engine, migration path, and accessible component contract.

    form builderschemaversioning
    30-second interview answer

    Define a versioned schema for fields, layout, validation, conditions, and data mapping; keep it independent from React component implementation. Build an editor with undo/redo and draft persistence, and a renderer that maps schema primitives to accessible design-system components. Validate on client and server, migrate old schemas, sandbox extensions, localize labels/errors, and observe completion and field failure without collecting sensitive values.

    Concise answer
  • Staff / PrincipalArchitecture3 min

    Design systems

    How would you introduce a design system across 300 inconsistent components without stopping delivery?

    Build accessible foundations, prove migration value, and create an incremental path with ownership and compatibility.

    design systemmigrationgovernance
    30-second interview answer

    Inventory usage and pain, establish tokens and a small set of accessible high-leverage primitives, and publish versioned APIs with examples, tests, and migration tooling. Adopt through touched-code and priority-flow migrations rather than a freeze. Provide compatibility wrappers and codemods, measure bundle and defect impact, establish contribution and deprecation governance, and partner with product teams so the system solves real delivery problems.

    Concise answer
  • Staff / PrincipalArchitecture3 min

    Microfrontends

    When do microfrontends help, and when should you avoid them?

    Use microfrontends for durable autonomous ownership boundaries, not as a cure for ordinary component modularity.

    microfrontendsteamsdeployment
    30-second interview answer

    Microfrontends can align large autonomous teams with independent deployment and bounded domains. They add runtime coordination, duplicated dependencies, routing and state contracts, inconsistent UX, observability complexity, and migration overhead. Prefer a modular monolith and shared build when teams can coordinate. If adopted, define integration boundaries, dependency policy, design-system compatibility, failure isolation, performance budgets, and cross-team contracts before choosing a runtime technique.

    Concise answer

Security, Errors & Reliability

XSS, trust boundaries, authentication, authorization, error boundaries, recovery, telemetry, and deployment safety.

Interview focus: Keep sensitive authority on the server, contain failures, and provide a recoverable user path with evidence.

  • AdvancedConcept3 min

    XSS

    What security risk does dangerouslySetInnerHTML introduce?

    React escapes text by default; bypassing that boundary requires trusted, context-appropriate sanitization.

    XSSdangerouslySetInnerHTMLsanitization
    30-second interview answer

    React normally escapes interpolated text, but dangerouslySetInnerHTML tells it to insert raw HTML. Untrusted or incorrectly sanitized content can execute XSS through elements, attributes, URLs, or mutation paths. Sanitize on a trusted boundary with an allowlist designed for HTML, keep the dependency updated, consider Trusted Types and CSP as defense in depth, and never treat client sanitization as authorization.

    Concise answer
  • SeniorArchitecture3 min

    Authorization

    Why can React authentication UI never enforce authorization by itself?

    Client route guards and hidden buttons improve UX, but every protected operation and response must be authorized server-side.

    authenticationauthorizationclient
    30-second interview answer

    All client code and state are controlled by the user, so hiding a route or button cannot grant or deny authority. The server must authenticate the request and authorize each operation and returned resource. Choose cookie or token storage based on threat model, CSRF, XSS, and deployment constraints; avoid placing secrets or privileged data in bundles. React renders the UX around security decisions—it is not the enforcement layer.

    Concise answer
  • Staff / PrincipalArchitecture3 min

    Supply chain

    How do you manage frontend dependency and client-bundle security?

    Minimize trusted code, review upgrades, scan artifacts, and assume every client-shipped value is public.

    dependenciesbundlesecrets
    30-second interview answer

    Keep dependency count and privileges small, pin and review lockfile changes, monitor advisories, generate provenance/SBOM where required, and test updates in staged builds. Restrict third-party scripts with CSP and isolation. Build-time public environment variables and source maps can expose data, so never bundle secrets. Security scanning supports—not replaces—ownership, threat modeling, and rapid patch/rollback capability.

    Concise answer
  • AdvancedDebugging3 min

    Error handling

    What do React Error Boundaries catch, and what do they not catch?

    Contain render-time failures below a boundary while handling event, network, and server failures in their own paths.

    Error Boundaryrender errorrecovery
    30-second interview answer

    An Error Boundary can catch rendering and lifecycle errors in its descendant tree and render fallback UI. It does not generally catch errors in event handlers, arbitrary async callbacks, server rendering, or the boundary itself; those need normal try/catch, rejected-state handling, framework error routes, or process-level reporting. Place boundaries around recoverable product regions and log component context without exposing sensitive data.

    Concise answer
  • SeniorScenario3 min

    Deployment reliability

    How should an application recover from a failed lazy-loaded chunk?

    Distinguish transient network failure from a stale HTML/new-deployment chunk mismatch and preserve a safe recovery path.

    lazy importdeploymentcache
    30-second interview answer

    Catch the rejected lazy import at an error boundary, report the asset URL and release, and offer a deliberate retry or reload. A one-time cache-busted retry may help transient failures; repeated automatic retries can loop. Deploy immutable hashed assets with sufficient retention so old HTML still resolves, coordinate CDN invalidation, and avoid deleting prior chunks immediately during rollout.

    Concise answer
  • Staff / PrincipalArchitecture3 min

    Observability

    What should production observability for a React application include?

    Correlate errors, performance, network, releases, and user journeys without collecting sensitive data.

    telemetryweb vitalserrors
    30-second interview answer

    Capture actionable JavaScript errors and component stacks, route and interaction performance, Core Web Vitals, long tasks, failed resources and APIs, and critical journey outcomes. Tag release, route, device class, and trace IDs so client and backend evidence joins. Sample high-volume signals, scrub personal data, define alert thresholds around user harm, and preserve source-map access securely. Telemetry must support rollback decisions, not merely dashboards.

    Concise answer

Senior React Production Scenarios

Real incidents involving render storms, slow input, memory growth, hydration, stale requests, large DOMs, and update overload.

Interview focus: Protect the user, collect a trace, narrow the failing layer, mitigate safely, and verify recovery.

  • SeniorScenario6 min

    Render diagnosis

    A dashboard re-renders almost the entire page whenever one filter changes. How do you investigate?

    Measure the interaction, locate the update owner, and narrow render reach before applying memoization.

    dashboardProfilerstate locality
    30-second interview answer

    Reproduce with realistic data and record a React profile. Identify which state or context update starts the commit, why unaffected widgets render, and whether expensive work or browser layout causes the delay. Move filter draft state to the smallest owner, split broad context, derive stable props, and memoize only measured expensive boundaries. Reprofile the same interaction and verify correctness, latency, and memory.

    Concise answer
  • SeniorScenario6 min

    Interaction latency

    Typing into a React search field feels delayed. How do you isolate the cause?

    Separate input control, expensive render, synchronous computation, request churn, and browser layout in one trace.

    input latencysearchPerformance panel
    30-second interview answer

    First determine whether the input's value update is blocked or only results lag. Record a browser trace and React profile while typing. Look for synchronous filtering, a high-owned state update rendering a large tree, request work on every keystroke, layout/paint, or third-party handlers. Keep input state urgent and local, defer or transition expensive results, debounce requests where appropriate, cancel stale work, and verify input latency.

    Concise answer
  • SeniorScenario7 min

    Memory

    A React app uses more memory after navigating between screens repeatedly. What do you investigate?

    Prove retained ownership with repeated navigation, heap evidence, and cleanup inspection rather than blaming React generically.

    memory leaknavigationcleanup
    30-second interview answer

    Create a repeatable navigate-away cycle and compare heap snapshots after forced idle/GC in a profiling environment. Inspect retained component data, detached DOM, event listeners, timers, WebSocket or observer subscriptions, global registries, query caches, and closures. Confirm Effect cleanup and library disposal. Separate expected cache warm-up from unbounded growth, fix the retaining owner, and rerun enough cycles to verify a stable plateau.

    Open deep dive →
  • SeniorScenario6 min

    State architecture

    A large Context provider causes application-wide renders. How do you redesign it?

    Separate cohesive responsibilities and notification scopes rather than wrapping the same giant value in useMemo.

    contextproviderselectors
    30-second interview answer

    Profile the provider updates and consumer set, then split values by ownership and change frequency—for example auth identity, theme, notification commands, and dashboard data. Narrow provider placement and separate state from stable actions where useful. Stabilize values only after the boundary is correct. Move high-frequency shared data to an external store with selectors so consumers subscribe to the exact slice they render.

    Concise answer
  • Staff / PrincipalScenario7 min

    Loading performance

    A React application displays quickly but becomes interactive very slowly. How do you analyze it?

    Inspect transfer, parse/compile, hydration, component work, and third-party long tasks along the actual device path.

    hydrationbundlelong task
    30-second interview answer

    Test a production build on representative mobile hardware and network. Trace bundle download, parse, compile, module initialization, hydration, React commits, long tasks, and third-party scripts. Use coverage and bundle analysis to remove or split code, move noninteractive work server-side where appropriate, stream useful HTML, defer third parties, and reduce hydration scope. Track interaction latency and errors, not only first paint.

    Concise answer
  • SeniorScenario6 min

    Async races

    Users occasionally see stale search results when typing quickly. What is happening?

    An older request completes after a newer request and wins a last-write race.

    race conditionAbortControllersearch
    30-second interview answer

    The input may start request A and then B; network completion order is independent, so A can arrive last and overwrite B. Abort obsolete requests to save work and guard every completion against the latest query or request sequence for correctness. Debounce request creation, not input rendering. A query library can centralize keys, cancellation, deduplication, cache freshness, and navigation behavior.

    Concise answer
  • SeniorScenario6 min

    Large lists

    A page with 50,000 rows freezes the browser. How should the architecture change?

    Bound both loaded data and mounted UI instead of trying to memoize an unbounded tree.

    virtualizationDOMpagination
    30-second interview answer

    Profile to confirm mount, DOM, layout, or data processing cost, then paginate or cursor-load data and virtualize visible rows with overscan. Move large sort/filter operations to a worker or server when appropriate, preserve stable IDs and selection outside mounted rows, and design focus, screen-reader, sticky-header, and scroll-restoration behavior. React.memo cannot make 50,000 DOM nodes cheap.

    Concise answer
  • SeniorScenario7 min

    Hydration

    A deployment introduces hydration mismatch warnings. How do you find the source?

    Compare raw server HTML with the first client tree and narrow nondeterminism by route, release, locale, and environment.

    hydrationdeploymentSSR
    30-second interview answer

    Reproduce with the production build and affected request context. Compare View Source with the browser's parsed DOM and React's first client inputs. Inspect dates, locale, random IDs, browser storage, feature flags, invalid nesting, request data, CDN rewrites, extensions, and mixed-version assets. Bisect the release and component boundary. Restore deterministic first output; do not broadly suppress warnings or switch the route to client-only rendering.

    Concise answer
  • Staff / PrincipalScenario7 min

    Real-time capacity

    A WebSocket dashboard receives more updates than the browser can render. How do you add backpressure?

    Protect the main thread by decoupling ingress rate, state publication, and visual refresh rate.

    WebSocketbackpressurebatching
    30-second interview answer

    Measure incoming rate, processing cost, queue depth, render cadence, and acceptable staleness. Coalesce superseded updates by entity, sample telemetry, publish at animation-frame or product-specific intervals, and use selector subscriptions. Bound queues and define drop, aggregate, resync, or disconnect behavior under overload. Move parsing to a worker if it is material, and expose lag so silent stale UI is not mistaken for real time.

    Open deep dive →
  • Staff / PrincipalScenario7 min

    Architecture diagnosis

    A component has 14 useEffect calls with intertwined dependencies. What does that suggest?

    Many effects are not automatically wrong, but intertwined dependencies often expose mixed ownership and indirect state choreography.

    useEffectarchitecturestate machine
    30-second interview answer

    Map each Effect to the external system it synchronizes. Remove derived-state and event-driven Effects, combine updates into explicit transitions, and split independent capabilities into components or focused Hooks with clear lifetimes. If several Effects coordinate one workflow, model it as a reducer or state machine. Keep genuinely independent subscriptions separate. Use tests and profiling to preserve behavior during incremental extraction.

    Open deep dive →
Mental modelFundamentalsEvergreen3 min

What actually happens when React renders a component?

Back to library

30-second interview answer

A render is React calling components to calculate the next UI description from props, state, and context. That calculation must stay pure and may be restarted. React then compares the next tree with the previous one, and during commit applies necessary host changes such as DOM mutations and refs. Browser layout and paint happen after React's work; component execution does not imply a DOM update.

How React behaves

A useful explanation starts with the trigger. An initial root render, local state update, ancestor update, consumed context change, or external-store notification schedules work. React calls components to produce the next element tree. Every call observes one fixed snapshot of props and state, which is why render code must remain a deterministic calculation rather than mutate the outside world.

React then relates the next tree to the previous tree. Element types, sibling position, and keys decide which component identities survive. This reconciliation work can call many components even when their eventual host output is unchanged. In concurrent rendering, React may pause, restart, or abandon the calculation; no partially calculated tree becomes visible.

Only commit makes the chosen result observable: React applies host mutations, updates refs, and runs effect lifecycle work. The browser then performs its own style, layout, paint, and compositing. That separation matters in production because a slow interaction may be expensive component calculation, a large commit, or browser layout—and each needs different evidence and a different fix.

One event, one queued render snapshot

TSX · React 19.2
function Counter() {
  const [count, setCount] = useState(0)

  function increment() {
    setCount(current => current + 1)
  }

  return <button onClick={increment}>Count: {count}</button>
}

Render and runtime behavior

  • The click handler queues an update; it does not mutate count in the current render.
  • React calls Counter again with the next state snapshot.
  • If the button text changed, React commits that text update; layout and paint belong to the browser.

Common mistakes

  • Equating a component function call with a DOM mutation.
  • Saying React always performs a full DOM diff after every setter.
  • Running subscriptions, mutation, or imperative DOM work during render.

Interviewer follow-ups

  • Can a component render without committing?
  • What can cause a child to render?
  • Where do layout Effects run relative to browser paint?

Senior-level perspective

A senior answer maps a symptom to the phase that can produce it. Use React DevTools for component and commit work, the browser trace for task/layout/paint work, and network evidence for delivery. Optimizing the wrong phase is common and expensive.

Key takeaways

  • Render calculates; commit mutates.
  • State and props are fixed for one render.
  • React work and browser work are separate profiling layers.
Mental modelFundamentalsEvergreen3 min

What does it mean that React state is a snapshot?

Back to library

30-second interview answer

Each render receives fixed state values. Calling a setter queues work for a future render; it does not change the state variable inside the current event handler or closure. That is why several setCount(count + 1) calls from one render all calculate from the same count. Functional updates express a transition from the queued previous value when the next state depends on it.

How React behaves

React gives each render a snapshot of state. Event handlers and callbacks created by that render close over the same snapshot, so calling a setter cannot rewrite the variable they already captured. The setter queues either a replacement value or an updater function for the next render.

Batching lets React process several queued updates before rendering. Three replacement updates calculated as count + 1 from one snapshot all request the same value. Three updater functions each receive the pending result of the previous updater, so they compose. This is queue semantics, not a timer trick and not mutation.

The model explains stale timers and requests too: a callback created during render N still sees render N. The fix depends on intent—functional updates for transitions from prior state, truthful dependencies when synchronization must restart, Effect Events for non-reactive Effect logic in React 19.2, or a ref for deliberately non-rendering mutable bookkeeping.

Replacement values versus updater functions

TSX · React 19.2
function Counter() {
  const [count, setCount] = useState(0)

  const addOne = () => {
    setCount(count + 1)
    setCount(count + 1)
    setCount(count + 1) // final value: 1
  }

  const addThree = () => {
    setCount(value => value + 1)
    setCount(value => value + 1)
    setCount(value => value + 1) // final value: +3
  }

  return <><button onClick={addOne}>+1</button><button onClick={addThree}>+3</button></>
}

Render and runtime behavior

  • Every value-form update in addOne is calculated from the same count snapshot.
  • Updater functions are queued and receive the pending state in order.
  • React normally batches the queue into one resulting render.

Common mistakes

  • Expecting a setter to mutate the current variable synchronously.
  • Using a ref to force state-like reads instead of fixing the transition model.
  • Calling flushSync routinely to recover imperative expectations.

Interviewer follow-ups

  • What would console.log(count) show after setCount?
  • When is a direct replacement preferable?
  • How does this relate to stale closures?

Key takeaways

  • One render sees one state snapshot.
  • Setters queue future work.
  • Use updater functions for prior-state transitions.
Mental modelAdvancedEvergreen3 min

What does React mean by component identity?

Back to library

30-second interview answer

React associates state with a component identity in the rendered tree, determined primarily by element type, position among siblings, and key. If that identity remains stable, React preserves state across renders. If the type or key changes, or the component moves to a different identity position, React treats it as a different instance, cleans up the old one, and initializes new state.

How React behaves

React does not store state inside a function declaration. It stores state for an identity position in the rendered tree. Element type, sibling position, and key tell React whether the next element represents the same conceptual component. Stable identity preserves state, DOM association, refs, and the ongoing Effect lifecycle.

Changing the type or key creates a new identity. React cleans up the old subtree and mounts the new one. This can be intentional—for example, keying an edit form by customer ID to reset its draft—but unstable keys, index keys in reorderable lists, or component definitions created inside render produce accidental remounts.

At architecture scale, ask what lifetime state belongs to. A chat draft may belong to a conversation ID rather than a screen position; selection in a virtualized table must survive row unmounting; a route cache may preserve a subtree intentionally. Identity is a product-lifetime decision, not only a list-warning fix.

Use a key when a domain identity should reset state

TSX · React 19.2
type Contact = { id: string; name: string }

function ContactEditor({ contact }: { contact: Contact }) {
  return <EditForm key={contact.id} initialContact={contact} />
}

// Selecting another contact creates a new form identity and draft.
// Do this deliberately; unstable keys would lose user input accidentally.

Render and runtime behavior

  • Same type, position, and key preserve the component identity and state.
  • A changed key unmounts the old identity and mounts a new one.
  • Keys are scoped to siblings and should come from stable domain data.

Common mistakes

  • Generating keys with Math.random or Date.now during render.
  • Using array indexes for reorderable stateful rows.
  • Defining component types inside another component.

Interviewer follow-ups

  • When is an index key safe?
  • How would you preserve drafts per tab?
  • Why does moving JSX between branches sometimes preserve state?

Key takeaways

  • State follows tree identity.
  • Keys participate in identity, not sorting.
  • Resetting state with a key should be deliberate.
HooksAdvancedEvergreen3 min

What is a stale closure in React, and why does it happen?

Back to library

30-second interview answer

Every render creates functions that close over that render's props and state snapshot. If a timer, listener, promise callback, or memoized function runs later, it still sees those captured values unless it is recreated with correct dependencies or reads the latest value through an intentional pattern. Fix the ownership or dependency model; do not suppress the linter and hope the closure stays current.

How React behaves

JavaScript closures retain the lexical values from the render that created them. React does not replace the inside of an old function when state changes; the next render creates new functions that close over the next snapshot. A timer, event listener, promise callback, or memoized function registered earlier can therefore observe old values.

The correct fix depends on why the callback exists. A state transition based on prior state should use a functional updater. An Effect that synchronizes a listener should declare reactive dependencies and resubscribe, or in React 19.2 move non-reactive event-like logic to useEffectEvent. A ref is appropriate when the external callback deliberately needs the latest value without making it render state, but it moves responsibility outside React's reactive checking.

Suppressing exhaustive-deps or wrapping everything in useCallback often freezes the bug in place. Trace the callback to its originating render, name which values should be reactive, and choose an architecture whose lifetime matches the external system.

A timer that increments from queued state

TSX · React 19.2
function Counter() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    const id = window.setInterval(() => {
      setCount(current => current + 1)
    }, 1000)
    return () => window.clearInterval(id)
  }, [])

  return <output aria-live="polite">{count}</output>
}

Render and runtime behavior

  • The interval callback is created once, but its updater receives the pending state when React processes it.
  • Cleanup clears the exact interval created by setup.
  • No count dependency is needed because the callback does not read count.

Common mistakes

  • Adding an empty dependency array to silence repeated setup while reading changing state.
  • Using a ref for every stale closure and bypassing reactive synchronization.
  • Assuming useCallback makes a function see current values automatically.

Interviewer follow-ups

  • How would this differ for a DOM event listener?
  • When should a ref hold the latest value?
  • What does useEffectEvent change?

Key takeaways

  • Closures capture one render's values.
  • Fix the lifetime and dependency model.
  • Functional updates solve prior-state transitions, not every closure problem.
EffectsFundamentalsEvergreen3 min

What is a React Effect?

Back to library

30-second interview answer

An Effect describes how a committed render synchronizes with an external system such as a subscription, browser API, timer, network connection, or third-party widget. React runs setup after commit, runs cleanup before resynchronizing with changed dependencies, and cleans up on unmount. If there is no external system, the code probably belongs in render or an event handler.

How React behaves

An Effect is a synchronization process caused by rendering. Setup connects the committed component state to something React does not own: a socket, media player, timer, observer, subscription, network connection, analytics integration, or third-party widget. The dependency list describes which reactive inputs require that process to resynchronize.

React calls cleanup before a changed setup and on unmount. Development Strict Mode performs an extra setup-cleanup-setup cycle so missing teardown becomes visible. If that breaks the integration, the setup and cleanup are not symmetric. A ref flag that prevents the second setup merely hides the lifecycle defect.

Effects are not the default home for computation or user actions. Derived values belong in render, and a purchase or form submission belongs in its event path. Removing an Effect often eliminates a stale intermediate commit, an extra network request, and a source of dependency bugs at the same time.

Synchronize a connection with one reactive identity

TSX · React 19.2
function Room({ roomId }: { roomId: string }) {
  useEffect(() => {
    const connection = connectToRoom(roomId)
    connection.open()
    return () => connection.close()
  }, [roomId])

  return <h2>Room {roomId}</h2>
}

Render and runtime behavior

  • After commit, setup opens the connection for the current roomId.
  • Before roomId changes are synchronized, cleanup closes the previous connection.
  • Unmount also closes the currently owned connection.

Common mistakes

  • Describing useEffect as a direct replacement for class lifecycle methods.
  • Omitting dependencies to force one-time execution.
  • Putting event-specific mutations in an Effect triggered by state flags.

Interviewer follow-ups

  • When would useLayoutEffect be required?
  • Why does Strict Mode reconnect in development?
  • How would you split two independent subscriptions?

Key takeaways

  • Effects synchronize external systems.
  • Dependencies describe reactive inputs.
  • Cleanup must undo one setup.
EffectsIntermediateEvergreen3 min

Why is an Effect that copies firstName and lastName into fullName state unnecessary?

Back to library

30-second interview answer

fullName is fully determined by current props, so calculate it during render. Storing it creates another source of truth: React first commits stale fullName, the Effect sets it, and React renders again. The dependency array only maintains the synchronization problem. Reserve state for independent information and Effects for external systems.

How React behaves

The fullName example has no external system and no independent state. firstName and lastName already determine the answer. Storing fullName makes React first render and commit an obsolete value, then run the Effect, queue another update, render again, and commit the correction. That is both extra work and an inconsistent source-of-truth model.

Calculate cheap derived data directly in the component. If a calculation is proven expensive and its inputs often repeat, memoization may cache it, but useMemo remains an optimization. If a value represents an editable draft that intentionally diverges from props, name that product behavior and define when it resets rather than calling it derived state.

Calculate derived display data during render

TSX · React 19.2
type NameProps = { firstName: string; lastName: string }

function Name({ firstName, lastName }: NameProps) {
  const fullName = [firstName, lastName].filter(Boolean).join(" ")
  return <span>{fullName}</span>
}

Render and runtime behavior

  • Each render calculates fullName from the same input snapshot.
  • No stale intermediate commit or Effect-triggered second render exists.
  • There is only one source of truth: the input props.

Common mistakes

  • Copying props into state whenever props change.
  • Using useMemo for trivial string concatenation.
  • Treating the dependency array as proof the duplicate state is safe.

Interviewer follow-ups

  • When is a draft legitimately independent state?
  • When would useMemo be justified?
  • How would you reset a draft for another entity?

Key takeaways

  • Derive cheap values in render.
  • Avoid duplicated truth and extra commits.
  • Name independent draft state explicitly.
EffectsSeniorEvergreen3 min

How do request race conditions happen in an Effect, and how do you prevent stale results?

Back to library

30-second interview answer

Effects can start request A, then request B after input changes; if A finishes last, it can overwrite B's newer result. Cleanup should abort obsolete work where supported, and the completion path must ignore results that no longer match the active request. In production, prefer a framework loader or query/cache layer that also handles deduplication, freshness, retries, and navigation races.

How React behaves

Network completion order is unrelated to the order in which requests started. If selecting Alice starts request A and selecting Bob starts request B, A can finish last and overwrite Bob's current result. An Effect cleanup runs when person changes, which gives the previous request a place to abort and marks its completion as obsolete.

Cancellation and correctness are related but distinct. AbortController can stop supported fetch work and save resources, but a response may already have completed or a promise continuation may already be queued. The resolution path should also prove it still represents the active request—using an ignore flag, sequence number, or cache key before committing data.

At product scale, route loaders and query caches centralize this problem with request identity, deduplication, freshness, retries, navigation cancellation, and shared results. A hand-written Effect is an implementation option, not the default architecture for all remote state.

Abort obsolete work and guard its result

TSX · React 19.2
useEffect(() => {
  const controller = new AbortController()
  let obsolete = false

  void fetchUser(personId, { signal: controller.signal })
    .then(user => {
      if (!obsolete) setUser(user)
    })
    .catch(error => {
      if (error.name !== "AbortError" && !obsolete) setError(error)
    })

  return () => {
    obsolete = true
    controller.abort()
  }
}, [personId])

Render and runtime behavior

  • Changing personId cleans up the prior request before starting the next Effect setup.
  • Abort saves work where supported; obsolete guards the state commit.
  • Unmount prevents the request from updating an abandoned screen.

Trade-offs and cost

  • A local Effect is small but repeats cache, retry, and navigation behavior.
  • A query layer adds dependency and policy but centralizes remote-state correctness.
  • Debouncing can reduce request volume but does not itself prevent out-of-order completion.

Common mistakes

  • Making the Effect callback async, which returns a promise instead of cleanup.
  • Relying on abort alone as the result-order correctness mechanism.
  • Retrying every failure and amplifying an unhealthy dependency.

Interviewer follow-ups

  • How would a query cache key this request?
  • When should stale data remain visible?
  • How do optimistic mutations change the model?

Key takeaways

  • Request order is not response order.
  • Cancel obsolete work and guard completion.
  • Shared server state usually deserves a data layer.
RenderingIntermediateEvergreen3 min

Why are keys necessary, and how do they affect state preservation?

Back to library

30-second interview answer

Keys tell React which sibling in the next list corresponds to which sibling in the previous list. A stable domain key lets state and DOM association follow an item through insertion, removal, and reordering. Keys need only be unique among siblings, but they must be stable across renders. Generating a new key during render makes every item appear new and resets state.

How React behaves

Within one sibling set, React needs a stable way to relate logical items across renders. Without an explicit key, position is the fallback identity. That works only while the list's logical identity matches position. Insertions, deletion, filtering, or sorting break the relationship and can move local state, uncontrolled input values, focus, and animation state onto the wrong item.

A good key comes from the domain record and remains stable for that record across renders. It does not need global uniqueness and is not passed as a normal prop. A changed key is an instruction to replace the identity, so it is also a useful deliberate reset mechanism when the product lifetime changes.

Keep row identity tied to data

TSX · React 19.2
type Task = { id: string; title: string }

function TaskList({ tasks }: { tasks: Task[] }) {
  return (
    <ul>
      {tasks.map(task => (
        <TaskRow key={task.id} task={task} />
      ))}
    </ul>
  )
}

Render and runtime behavior

  • Reordering tasks preserves each TaskRow identity by task.id.
  • Removing one task removes only that identity.
  • Generating a key at render time would remount every row.

Common mistakes

  • Using array index for sortable or filterable stateful content.
  • Assuming keys are only an optimization or warning fix.
  • Passing duplicate keys among siblings.

Key takeaways

  • Keys express sibling identity.
  • Stable domain IDs preserve state correctly.
  • A changed key deliberately resets a subtree.
PerformanceSeniorEvergreen3 min

How do you investigate a slow React interaction before optimizing it?

Back to library

30-second interview answer

Reproduce the exact interaction with production-like data and record a browser Performance trace plus React DevTools profile. Determine whether time is in JavaScript, React rendering, a commit, layout/paint, network, or third-party work. Identify why the expensive subtree rendered, form one hypothesis, make the smallest architectural or algorithmic change, and remeasure the user-visible latency and regressions.

How React behaves

Begin with a user-visible symptom and a repeatable interaction under production-like data. A vague report that React is slow cannot distinguish network delay, input blocking, JavaScript work, component rendering, DOM mutation, layout, paint, memory pressure, or third-party code. Capture a browser Performance trace and a React DevTools profile for the same interaction.

In React's profile, identify the relevant commits, expensive components, and why they rendered. In the browser trace, locate long tasks, script stacks, style/layout, paint, and network timing. Broad component work often points to state or context placed too high; a single expensive component may contain algorithmic work; a small React commit followed by large layout points to DOM/CSS architecture.

Form one hypothesis and change one limiting factor: move state, change the algorithm, split context, virtualize, cache a proven calculation, reduce DOM, or move blocking work. Then rerun the same trace. Report both improvement and cost—memory, code complexity, stale-data risk, or delayed work—because an optimization that only moves latency is not complete.

Investigation path

  1. 01Define the exact interaction, dataset, device, and latency symptom.
  2. 02Record React and browser profiles for the same reproduction.
  3. 03Separate network, scripting, render, commit, layout, paint, and third-party time.
  4. 04Trace the expensive work to its update owner and input change.
  5. 05Apply one bounded fix and compare the same metrics.
  6. 06Verify memory, correctness, accessibility, and regression risk.

Common mistakes

  • Adding useMemo or React.memo before measuring the calculation or render path.
  • Profiling a development build and treating timings as production behavior.
  • Ignoring browser layout and third-party scripts because the app uses React.

Interviewer follow-ups

  • What does a React commit duration exclude?
  • How would you profile a production-only slowdown?
  • When can memoization increase memory or latency?

Senior-level perspective

Staff-level performance work adds budgets, representative lab and field telemetry, release comparison, ownership, and a rollback threshold. The durable output is not one faster component; it is a system that catches regressions before users do.

Key takeaways

  • Start from a repeatable user symptom.
  • Correlate React and browser evidence.
  • Optimize one proven limiting factor and verify.
PerformanceSeniorEvergreen3 min

How would you render 100,000 rows without freezing the browser?

Back to library

30-second interview answer

Use windowing: render only visible rows plus a small overscan buffer, represent total height with spacers, and recycle positions as the viewport moves. Define stable item identity, row measurement for variable heights, keyboard and screen-reader behavior, focus retention, and scroll restoration. Pagination bounds data transfer; virtualization bounds DOM and render work. React.memo alone leaves the huge DOM mounted.

How React behaves

A 100,000-row problem is an unbounded-work problem, not primarily a memoization problem. Even if every row component bails out, the browser still owns a huge DOM, style calculation, layout structures, accessibility tree, and memory footprint. Virtualization bounds the mounted representation to the viewport plus overscan.

A virtualizer maps scroll offset to a visible item range, positions those rows inside a container that represents total size, and recycles positions as the user moves. Fixed-height rows are straightforward; variable-height content needs measurement, estimation, and correction without visible jumps. Stable domain identity must remain separate from recycled visual slots.

Production design includes more than speed: keyboard navigation cannot lose focus when a row leaves the window; assistive technology needs meaningful position and count semantics; selection must survive unmounting; sticky headers, expanded rows, deep links, print/export, and scroll restoration need explicit behavior. Pagination controls data transfer, while virtualization controls rendering and DOM size.

Render and runtime behavior

  • Only a bounded visible range becomes React elements and host nodes.
  • Scrolling updates the window and repositions or replaces mounted rows.
  • Selection and domain state must live outside row mount lifetime.

Trade-offs and cost

  • Windowing reduces DOM work but adds measurement and focus complexity.
  • Overscan smooths fast scrolling at the cost of extra mounted rows.
  • Pagination improves navigation and data bounds; infinite scroll may fit continuous exploration better.

Common mistakes

  • Rendering every row and wrapping Row in React.memo.
  • Keying recycled rows by visible index rather than domain identity.
  • Ignoring keyboard, screen-reader, print, and scroll-restoration behavior.

Interviewer follow-ups

  • How do variable row heights change the design?
  • How would you retain focus when the active row scrolls out?
  • When would pagination be preferable?

Senior-level perspective

Choose a capacity budget: maximum loaded records, mounted rows, retained selection, and scroll-history depth. Validate on lower-end devices and define a non-virtual fallback for print, export, or assistive workflows when needed.

Key takeaways

  • Bound mounted UI, not just component calculations.
  • Keep item state independent from row mount lifetime.
  • Accessibility and scroll behavior are architectural requirements.
Modern ReactAdvancedStable in React 19.23 min

What does concurrent rendering mean in React, and is it parallel rendering?

Back to library

30-second interview answer

Concurrent rendering lets React prepare multiple versions of UI with priority-aware, interruptible render work. A lower-priority render can pause or restart so an urgent input update stays responsive; only a completed consistent tree commits. It does not mean component functions run simultaneously on multiple JavaScript threads. Purity is what makes restartable calculation safe.

How React behaves

Concurrent rendering is a scheduling capability. React can prepare a lower-priority tree, pause it when urgent work arrives, restart with newer inputs, and commit only a completed consistent result. JavaScript component code is not executing in parallel across CPU cores; the benefit is that render work no longer has to monopolize the main thread until completion.

Transitions mark updates whose visual destination can wait while urgent input remains responsive. Deferred values let one part of the tree temporarily use an older value while a lower-priority render catches up. Suspense boundaries coordinate what can remain visible and what fallback appears when compatible work is not ready.

Concurrency does not fix a 200 ms synchronous calculation: a long uninterrupted JavaScript task still blocks. Reduce or move that work, virtualize large UI, or use a worker where appropriate. Purity remains essential because React must be free to repeat or discard render calculations without leaking side effects.

Keep input urgent and results non-urgent

TSX · React 19.2
function Search({ items }: { items: string[] }) {
  const [query, setQuery] = useState("")
  const [isPending, startTransition] = useTransition()
  const [filter, setFilter] = useState("")

  function updateQuery(next: string) {
    setQuery(next)
    startTransition(() => setFilter(next))
  }

  const matches = items.filter(item => item.includes(filter))
  return <SearchView query={query} onQueryChange={updateQuery} items={matches} pending={isPending} />
}

Render and runtime behavior

  • The controlled input value updates urgently.
  • React may interrupt and restart the results render for newer filter input.
  • Only a completed tree commits; intermediate render work stays invisible.

Common mistakes

  • Calling concurrency parallel rendering or a web worker.
  • Putting the controlled input update itself inside a transition.
  • Expecting a transition to make expensive JavaScript execute faster.

Key takeaways

  • Concurrency is priority-aware scheduling.
  • Urgent and non-urgent updates can have different render treatment.
  • Long synchronous work still needs architectural reduction.
Modern ReactSeniorStable in React 19.23 min

How does React Compiler change the memoization discussion?

Version context: React Compiler 1.0 became stable in October 2025 and supports incremental adoption; integrations remain build-tool specific.

Back to library

30-second interview answer

React Compiler 1.0 is a stable build-time optimizer that analyzes component and Hook code and applies granular memoization automatically. It reduces routine useMemo, useCallback, and React.memo work, but it does not fix expensive algorithms, huge DOMs, network waterfalls, or broken state ownership. Adopt it incrementally, respect the Rules of React, test behavior, and verify performance rather than assuming every component improves.

How React behaves

React Compiler 1.0 is a stable build-time optimizer. It analyzes data flow and mutability in components and Hooks, validates Rules-of-React assumptions, and inserts granular memoization where its analysis determines values or JSX can be reused. This can be more precise than manually wrapping whole components or calculations.

The compiler changes the default conversation around useMemo, useCallback, and React.memo: new compiler-enabled code can usually rely on automatic optimization, while manual memoization remains available for precise identity requirements and existing code should not be stripped mechanically. Correctness must never depend on a cache React is allowed to discard.

It does not solve algorithmic complexity, network waterfalls, oversized bundles, huge DOMs, layout cost, broad state ownership, or third-party work. Adoption still needs compatibility linting, representative tests, performance baselines, staged rollout, exact version policy where risk warrants it, and an escape hatch for incompatible code.

Trade-offs and cost

  • Automatic memoization reduces boilerplate and stale-dependency risk but adds a build transform and rollout surface.
  • Manual memoization offers local control but can obscure data flow and retain values unnecessarily.
  • Compiler upgrades can change optimization output, so correctness must follow the Rules of React.

Common mistakes

  • Claiming the compiler prevents every re-render.
  • Removing all existing memoization without behavior and performance testing.
  • Using compiler optimization as a substitute for profiling or sound state architecture.

Interviewer follow-ups

  • What problems remain after enabling the compiler?
  • Would you remove existing useMemo calls?
  • How would you roll it out across a monorepo?

Senior-level perspective

Treat compiler adoption as a platform change: compatibility inventory, lint gates, representative performance cohorts, release pinning, escape-hatch ownership, and upgrade playbooks matter more than a before/after demo component.

Key takeaways

  • Compiler 1.0 is stable build-time automatic memoization.
  • Optimization never becomes application semantics.
  • Measure and roll out; do not assume architecture problems disappear.
Modern ReactSeniorFramework-dependent3 min

What are React Server Components, and where is the client boundary?

Version context: Server Components are stable in React 19; production routing, caching, server functions, and bundling are supplied by a framework, whose underlying RSC APIs require careful version alignment.

Back to library

30-second interview answer

Server Components render ahead of the client bundle in a separate environment, can access server-side data, and send rendered output rather than their component code to the browser. Interactive state, Effects, and browser APIs belong in Client Components. Values crossing the boundary must be serializable by the integration. React 19 stabilizes the component model, while bundler/framework implementation APIs can still change between minors.

How React behaves

A Server Component executes in a server-like build or request environment and does not ship its component code to the browser. It can access server data and libraries, await during rendering, and pass serializable props or rendered children into Client Components. Client Components own interaction, state, Effects, and browser APIs; they can still participate in server HTML rendering through a framework.

Server Components and SSR are orthogonal. SSR produces initial HTML; RSC changes the component module graph and payload so some components never enter the client bundle. A framework composes routing, caching, data mutations, streaming, deployment, and bundling around React's model. The React 19 Server Component contract is stable, while the low-level bundler/framework implementation APIs can change between React minor versions.

Move a boundary only when it improves data locality, removes meaningful client JavaScript, or protects server-only dependencies while preserving the product interaction. Serialization, extra server work, navigation latency, cache invalidation, and network boundaries are costs. Any data passed to the client is client-visible, so the boundary is not automatic authorization.

Render and runtime behavior

  • Server Component code is not included in the client bundle.
  • Client Components can receive serializable data and rendered Server Component children.
  • Framework integration decides routing, caching, mutation, and deployment behavior.

Trade-offs and cost

  • Less client JavaScript and direct data access versus server capacity and boundary complexity.
  • Better data locality versus serialization limits and navigation round trips.
  • Stable React component model versus version-sensitive framework/bundler internals.

Common mistakes

  • Saying use server marks a Server Component; it marks Server Functions.
  • Equating Server Components with SSR or assuming Client Components never render on the server.
  • Passing secrets to a Client Component because the parent ran on the server.

Interviewer follow-ups

  • When would a Client Component be the better boundary?
  • How do RSC and hydration interact?
  • What data can cross the boundary?

Key takeaways

  • RSC changes the client module graph; SSR produces HTML.
  • Interactivity remains in Client Components.
  • Framework behavior must be labelled separately from React.
Modern ReactSeniorEvergreen3 min

What is hydration, and what causes hydration mismatches?

Back to library

30-second interview answer

Hydration lets React attach behavior to server-rendered HTML while reusing that DOM. The first browser render must match the server output in structure, text, attributes, and stable IDs. Dates, locale, random values, browser-only storage, invalid HTML, request-specific data, extensions, and CDN rewrites can diverge. Find and remove the nondeterministic source; suppression is only a narrow escape hatch.

How React behaves

Server rendering sends HTML the browser can display before all client code is ready. Hydration creates a React root over that existing HTML, matches it to the first client render, attaches event behavior, and makes the tree interactive. The contract is deterministic first output: equivalent structure, text, attributes, and IDs for the same boundary.

Mismatches come from values that differ by environment or time—Date, Math.random, locale, browser storage, viewport APIs, request data, feature flags—or from invalid HTML that the browser reparses. Extensions and CDN transforms can mutate the document before React sees it. A Client Component in a framework may still contribute to server HTML, so a typeof window branch during render can produce two different trees.

Fix the source by passing stable server values, delaying browser-only state until after hydration, using useId for stable accessibility IDs, and correcting invalid markup. suppressHydrationWarning is a narrow one-level escape hatch for unavoidable leaf differences; it is not a repair strategy. Production diagnosis compares raw response, parsed DOM, first client inputs, route, locale, release, and asset versions.

Render and runtime behavior

  • The server sends displayable HTML before client interactivity is attached.
  • hydrateRoot expects the first client-rendered tree to match that HTML.
  • Later state and Effects can intentionally change the UI after hydration completes.

Common mistakes

  • Reading localStorage or matchMedia in the first render and returning different markup.
  • Using Math.random for rendered IDs instead of useId or stable data.
  • Suppressing a subtree-wide mismatch or disabling SSR instead of finding nondeterminism.

Interviewer follow-ups

  • How is hydration different from initial client rendering?
  • Can invalid HTML create a mismatch before React runs?
  • How would you debug a production-only mismatch?

Key takeaways

  • Hydration reuses server HTML and attaches React behavior.
  • The first client output must match the server output.
  • Fix nondeterminism; suppress only narrow unavoidable differences.
Testing & a11ySeniorEvergreen3 min

How would you design an accessible autocomplete?

Back to library

30-second interview answer

Use the ARIA combobox pattern with a labelled input, controlled popup state, listbox relationship, active option indication, and documented Arrow, Enter, Escape, and Tab behavior. Keep DOM focus predictable, announce result count/loading changes without noise, preserve typed text, and expose errors. Add debounce, cancellation, stale-result guards, caching, and mobile/touch behavior without breaking keyboard semantics.

How React behaves

An autocomplete is a composite interaction, not an input plus an absolutely positioned list. Model text input, popup visibility, active option, selected value, results, loading, empty, error, and composition/input-method behavior explicitly. The input keeps a reliable accessible name and the popup follows the WAI-ARIA combobox pattern.

Keyboard behavior includes Down/Up navigation, Enter selection, Escape dismissal, Tab movement, and predictable Home/End behavior where applicable. Decide whether DOM focus stays on the input with aria-activedescendant or moves into options, then implement the pattern consistently. Announce result count or loading changes through a restrained live region without repeating every keystroke.

Remote behavior needs debounce, AbortController, an arrival-order guard, a minimum query policy, bounded results, cache identity, and clear failure/retry. Track time to first useful suggestion, stale response drops, request rate, selection completion, and accessibility errors. Link to the existing JavaScript typeahead controller for transport mechanics rather than duplicating it here.

Investigation path

  1. 01Define the input, active option, selection, popup, and remote-query state machine.
  2. 02Implement and test keyboard, focus, accessible names, relationships, and announcements.
  3. 03Add debounce, cancellation, stale guards, cache, empty/error, and retry behavior.
  4. 04Test touch, screen readers, IME composition, slow network, and rapid input.
  5. 05Measure input latency, request amplification, suggestion latency, and completion.

Common mistakes

  • Building keyboard behavior after visual completion rather than into the state model.
  • Moving focus unpredictably between the input and portal options.
  • Debouncing the controlled input value and making typing itself lag.

Interviewer follow-ups

  • How do you handle out-of-order responses?
  • How would virtualized suggestions affect aria-activedescendant?
  • What should a screen reader announce?

Key takeaways

  • Accessibility is part of the interaction state machine.
  • Input responsiveness and request rate are separate concerns.
  • Cancellation saves work; stale guards preserve correctness.
ProductionSeniorEvergreen7 min

A React app uses more memory after navigating between screens repeatedly. What do you investigate?

Back to library

30-second interview answer

Create a repeatable navigate-away cycle and compare heap snapshots after forced idle/GC in a profiling environment. Inspect retained component data, detached DOM, event listeners, timers, WebSocket or observer subscriptions, global registries, query caches, and closures. Confirm Effect cleanup and library disposal. Separate expected cache warm-up from unbounded growth, fix the retaining owner, and rerun enough cycles to verify a stable plateau.

How React behaves

First prove the shape of growth. Repeatedly navigate into and out of the screen with a fixed workload, allow idle time, and compare heap snapshots or allocation timelines. A warm cache may reach a plateau; a leak keeps retaining each screen generation. Browser memory includes JavaScript heap, DOM, images, workers, WebAssembly, and native library allocations, so one metric is not enough.

Trace retaining paths for detached DOM nodes, component data, listeners, timers, observers, sockets, promises, and closures. Inspect Effect cleanup, but also global event buses, module-level registries, query caches, state stores, portal roots, third-party charts, and pending queues. React cannot free an object while another owner still references it.

Fix the ownership boundary: unsubscribe, clear, abort, dispose library instances, bound caches and history, or change worker lifecycle. Do not call garbage collection as a fix; GC cannot collect reachable objects. Verify with the same repeated cycle until memory reaches a stable range and confirm that cleanup did not break reconnection or navigation behavior.

Investigation path

  1. 01Reproduce a fixed navigation cycle and distinguish warm-up from unbounded growth.
  2. 02Capture heap snapshots/allocation timelines and inspect retaining paths.
  3. 03Audit Effects, listeners, timers, observers, sockets, caches, stores, portals, and libraries.
  4. 04Fix the retaining owner or add an explicit capacity/lifecycle bound.
  5. 05Repeat the cycle and verify a stable plateau plus correct reconnection behavior.

Common mistakes

  • Assuming every increasing browser memory graph is a React leak.
  • Calling manual GC or forcing remounts without finding the retaining reference.
  • Cleaning up Effects while leaving module caches or third-party registries unbounded.

Interviewer follow-ups

  • How do detached DOM nodes appear in a heap snapshot?
  • How would you distinguish a useful cache from a leak?
  • What if native chart memory grows outside the JS heap?

Senior-level perspective

Production readiness adds memory telemetry by route and release, long-session synthetic tests, cache budgets, disposal contracts for third-party components, and safe worker recycling only as mitigation—not as a substitute for root cause.

Key takeaways

  • Prove retention over a repeatable lifecycle.
  • Find the owner that keeps objects reachable.
  • Fix lifecycle or capacity, then verify a plateau.
ProductionStaff / PrincipalEvergreen7 min

A WebSocket dashboard receives more updates than the browser can render. How do you add backpressure?

Back to library

30-second interview answer

Measure incoming rate, processing cost, queue depth, render cadence, and acceptable staleness. Coalesce superseded updates by entity, sample telemetry, publish at animation-frame or product-specific intervals, and use selector subscriptions. Bound queues and define drop, aggregate, resync, or disconnect behavior under overload. Move parsing to a worker if it is material, and expose lag so silent stale UI is not mistaken for real time.

How React behaves

A transport can deliver data faster than a person can perceive and faster than the main thread can parse, reduce, render, and paint it. Calling setState for every message couples ingress rate directly to React work, grows queues during bursts, and can make the dashboard both delayed and misleading.

Insert a bounded processing layer between transport and UI. Normalize messages, coalesce superseded updates by entity, aggregate or sample telemetry, and publish immutable snapshots at a deliberate cadence such as requestAnimationFrame or a product-specific interval. Selector subscriptions let each widget render only the slice it uses. Move expensive parsing or aggregation to a worker when the measured main-thread cost justifies it.

Backpressure requires a policy: when the buffer is full, drop obsolete point updates, aggregate them, ask the server for a slower stream, disconnect and resync, or shed lower-priority channels. Track inbound rate, buffer depth, dropped/coalesced count, snapshot age, render cadence, and end-to-end lag so the interface can disclose stale data instead of silently presenting it as live.

Render and runtime behavior

  • Transport updates accumulate outside broad component state.
  • A bounded publisher exposes snapshots at a rate the UI can sustain.
  • Selectors notify only components whose rendered slice changed.

Trade-offs and cost

  • Sampling improves responsiveness but intentionally loses intermediate detail.
  • Coalescing preserves the latest entity state but not every event history.
  • Workers isolate CPU work but add serialization and lifecycle cost.

Common mistakes

  • Assuming React's automatic batching supplies transport backpressure.
  • Keeping an unbounded message or chart history in client memory.
  • Dropping updates without exposing data age or a resynchronization path.

Interviewer follow-ups

  • Which updates may be dropped safely?
  • How would you recover after a sequence gap?
  • When should the server aggregate instead?

Senior-level perspective

Staff reasoning covers an end-to-end capacity contract: server publish policy, transport sequence, client buffer, aggregation, render budget, reconnect/resync, and SLOs for freshness rather than raw message delivery.

Key takeaways

  • Decouple ingress rate from render rate.
  • Every queue needs a bound and overload policy.
  • Expose freshness and lag as product state.
ProductionStaff / PrincipalEvergreen7 min

A component has 14 useEffect calls with intertwined dependencies. What does that suggest?

Back to library

30-second interview answer

Map each Effect to the external system it synchronizes. Remove derived-state and event-driven Effects, combine updates into explicit transitions, and split independent capabilities into components or focused Hooks with clear lifetimes. If several Effects coordinate one workflow, model it as a reducer or state machine. Keep genuinely independent subscriptions separate. Use tests and profiling to preserve behavior during incremental extraction.

How React behaves

The count alone is not the defect; fourteen independent integrations could legitimately require fourteen Effects. The smell is intertwined dependencies and Effects that set state only to trigger other Effects. That pattern usually means one component owns several workflows, derived values have been stored, and event transitions became indirect synchronization chains.

Create an Effect inventory. For each one, name the external system, setup, cleanup, and reactive identity. Delete derivation Effects, move user-caused actions to event handlers, consolidate atomic domain transitions in a reducer or state machine, and extract coherent external lifecycles into focused Hooks or child components. Keep independent subscriptions separate so changing one does not restart another.

Refactor incrementally behind behavior tests and production telemetry. Splitting a large component into files without changing ownership only relocates the coupling. The desired outcome is a smaller number of understandable state machines and synchronization boundaries, not a target Effect count.

Investigation path

  1. 01List every Effect with its external system, setup, cleanup, and dependencies.
  2. 02Remove derived-state and event-driven Effects.
  3. 03Model multi-field transitions as explicit reducer/state-machine events.
  4. 04Extract cohesive lifecycles; keep independent synchronization separate.
  5. 05Protect behavior with tests and compare render/subscription telemetry.

Common mistakes

  • Combining unrelated Effects only to reduce the count.
  • Suppressing dependencies to stop cycles.
  • Splitting files while leaving one shared state-and-effect graph intact.

Interviewer follow-ups

  • When should two Effects remain separate?
  • Would a reducer eliminate Effects?
  • How do you migrate safely without changing user behavior?

Senior-level perspective

At Staff level, repeated Effect tangles across teams often indicate missing domain APIs, data-layer policy, or platform primitives. Fix the shared boundary and migration path, not only one component.

Key takeaways

  • Inventory synchronization by external system.
  • Replace indirect state choreography with explicit transitions.
  • Optimize ownership clarity, not Effect count.

How this React interview hub is maintained

Foundational questions test durable rendering models; intermediate questions test state and component design; senior questions test performance and production diagnosis; Staff questions test platform, migration, capacity, and organizational judgment. Level labels are not claims about any employer's proprietary interview frequency.

  • Version-sensitive claims are checked against current official React documentation and release notes.
  • React behavior is separated from JavaScript, browser, and framework responsibility throughout the page.
  • Counts, categories, scenarios, topics, and deep dives are derived from the typed catalog.
  • Existing hydration, autocomplete, infinite-scroll, Virtual DOM, debounce, and component articles are linked instead of copied.

Primary React references

Connect React behavior to frontend system decisions

Pair the render model with JavaScript scheduling, browser performance, distributed reliability, and architecture judgment. React is one layer of the production system.

Build a study roadmap