React interview questions and answers in 2026 go well past "what is JSX?" Interviewers expect you to reason about hooks as synchronization, when useMemo helps vs hurts, how Server Components change data fetching, and how you would build a search bar or todo list under time pressure. React JS interview questions and answers loops at product companies blend fundamentals, architecture judgment, and React coding interview questions—live components, state fixes, and performance debugging.
Below are 40+ React interview questions covering fundamentals, hooks, state, performance, React 19.2, and live coding scenarios. Technical sections include a strong answer sample you can say aloud. This article owns beginner and mid fundamentals — JSX, props/state, hooks, forms, lists/keys, routing, testing, and React 19.2 topics including useEffectEvent and <Activity />. For scenario-based senior prep (Fiber, concurrency, React Compiler, RSC architecture, hydration, performance profiling, and production scenarios), see interview questions on React JS for experienced developers.
Interview context and how to prepare
What React interviews actually test
React interviews test whether you can build interactive UIs that stay correct as state and data change—not whether you memorized every API from 2018.
| Layer | What interviewers probe |
|---|---|
| Fundamentals | Components, JSX, props, state, one-way data flow |
| Hooks | useState, useEffect, dependencies, custom hooks |
| Rendering | Reconciliation, keys, memoization judgment |
| State & data | Local vs server state, Context, TanStack Query |
| Performance | Re-render causes, useMemo/useCallback, code splitting |
| Modern React | Suspense, transitions, RSC, React 19 Actions |
| Coding | Small components live—forms, lists, fetch patterns |
| Level | Emphasis |
|---|---|
| Junior | Hooks basics, props, simple lists/forms |
| Mid | Effects, routing, testing, API integration |
| Senior | Architecture, performance, RSC, accessibility, system trade-offs |
Coding rounds vs theory rounds
Theory rounds ask definitions—Virtual DOM, lifecycle in a hooks world, controlled inputs.
Coding rounds ask you to ship in 30–45 minutes:
| Common exercise | What they watch |
|---|---|
| Todo / filter list | State shape, keys, immutability |
| Search with debounce | Effects, cleanup, stale closures |
| Fetch and display | Loading/error, abort, query library mention |
| Form validation | Controlled fields, submit handling |
| Fix a buggy component | Missing deps, mutating state, wrong key |
Strong candidates think aloud, state assumptions, and write tests or edge-case handling when time allows.
A typical React interview loop
| Round | Duration | Focus |
|---|---|---|
| Recruiter / HM | 30 min | Projects, stack, team UI standards |
| React deep dive | 45–60 min | Hooks, rendering, state architecture |
| Live coding | 45–90 min | Component exercise, debug session |
| System design (senior) | 45 min | Frontend architecture, data layer, perf |
| Behavioral | 30 min | Collaboration, incidents, code review |
Take-home UIs often include README trade-offs and test coverage—not only pixels.
A realistic 4–6 week React prep plan
| Week | Focus | Output |
|---|---|---|
| 1 | Core React — JSX, props, state, lists, forms | Rebuild todo without tutorial |
| 2 | Hooks depth — effects, refs, custom hooks | useDebounce, useFetch patterns |
| 3 | Data — TanStack Query, error boundaries | List page with loading/error/empty |
| 4 | Performance & testing — RTL, memo judgment | Fix one unnecessary re-render case |
| 5 | React 18/19 — Suspense, transitions, RSC basics | Explain client vs server component split |
| 6 | Coding drills + mock | 3 timed exercises; 2 STAR stories |
Build one small app (dashboard, catalog, or admin table) you can demo and defend.
React fundamentals
What is React and why use it?
What interviewers are testing: Whether you understand React's declarative, component-based model and can explain what React provides versus what a framework such as Next.js adds.
React is a JavaScript library for building user interfaces with a component-based model and declarative rendering—you describe UI as a function of state, React updates the DOM when state changes.
| Benefit | Detail |
|---|---|
| Components | Reusable, composable UI units |
| Declarative UI | Less manual DOM patching |
| Ecosystem | Routing, state, meta-frameworks (Next.js, Remix) |
| Talent pool | Widely adopted in product companies |
React is a library, not a full framework—you choose routing, data layer, and styling.
A strong answer is:
React lets teams compose UIs from components with predictable one-way data flow; I use it when rich client interactivity and a large ecosystem matter more than a batteries-included monolith framework.
What is JSX?
What interviewers are testing: Whether you can explain JSX as compile-time syntax sugar, automatic vs classic transforms, and why it is not HTML.
JSX is syntax sugar that looks like HTML inside JavaScript. Build tools transform it into JavaScript calls understood by the React JSX runtime. Older tooling used explicit React.createElement() calls; modern projects normally use the automatic JSX transform, so importing React solely for createElement is no longer required.
function Greeting({ name }) {
return <h1>Hello, {name}</h1>;
}Rules interviewers mention:
- One parent element or Fragment (
<>...</>) classNameinstead ofclass- JavaScript expressions in
{curly braces} - Self-closing tags required (
<img />)
JSX is not HTML—attributes and casing follow React conventions.
A strong answer is:
JSX is declarative syntax compiled to JavaScript function calls—it keeps UI structure readable while staying in the JavaScript type and tooling world.
What is the Virtual DOM and how does reconciliation work?
What interviewers are testing: Whether you can explain reconciliation and Fiber without overstating React as always computing the smallest possible DOM patch set.
React keeps a lightweight tree representing UI. On state change:
- React calls your component functions to produce a new element tree
- Diffs new tree vs previous (reconciliation)
- React reconciles the new element tree against the previous tree and commits the necessary host/DOM changes
Fiber (React 16+) enables incremental work, priorities, and concurrent rendering—reconciliation can pause and resume.
| Concept | Interview point |
|---|---|
| Not magic speed | Large lists still need stable keys and intentional memoization |
| Keys | Help match list items across renders |
| Batched updates | React 18 expanded automatic batching beyond React event handlers to updates from sources such as promises and timers when using the modern root API |
A strong answer is:
React builds a new element tree each render, reconciles it against the previous tree, and commits the necessary DOM changes—keys and structure determine whether list updates stay efficient.
What is the difference between props and state?
What interviewers are testing: whether you treat props as read-only parent input and state as component-owned data that triggers re-renders.
| Props | State | |
|---|---|---|
| Source | Parent passes down | Owned inside component (or hook) |
| Mutability | Read-only for child | Updated via setter (setState, useState) |
| Purpose | Configuration, callbacks | UI that changes over time |
One-way data flow: parent state → child props → events call parent setters.
Anti-pattern: child mutates props object directly.
A strong answer is:
Props are inputs from parents; state is local mutable UI data updated immutably through setters—data flows down, events flow up.
Controlled vs uncontrolled components?
What interviewers are testing: whether you choose controlled inputs when React must own form state and uncontrolled refs for simple file or legacy integrations.
| Type | Who owns input value |
|---|---|
| Controlled | React state drives value + onChange |
| Uncontrolled | DOM holds value; read via ref |
// Controlled
const [email, setEmail] = useState("");
<input value={email} onChange={(e) => setEmail(e.target.value)} />
// Uncontrolled
const inputRef = useRef(null);
<input ref={inputRef} defaultValue="" />Prefer controlled for validation, instant feedback, and predictable tests. Uncontrolled fits simple forms or file inputs.
A strong answer is:
Controlled inputs bind value to state for validation and single source of truth; uncontrolled defer to the DOM and refs when that is simpler.
Hooks and component behavior
Explain useState — how does React schedule updates?
What interviewers are testing: Whether you understand state as a render snapshot, batching, and when functional updates are required.
useState returns [value, setter]. Updates are scheduled—React may batch multiple setters in one render.
const [count, setCount] = useState(0);
function increment() {
setCount((c) => c + 1); // functional update — safe when next state depends on previous
}| Pattern | When |
|---|---|
setCount(5) |
Absolute new value |
setCount(c => c + 1) |
Depends on previous state |
Lazy init useState(() => expensive()) |
Heavy initial computation once |
Calling the setter schedules another render; it does not change the state variable captured by the currently executing render.
A strong answer is:
useStategives each render a snapshot of local state. I use functional updates when the next state depends on the previous value, especially when updates may be batched.
Explain useEffect — dependencies, cleanup, and pitfalls.
What interviewers are testing: whether you model effect dependencies, cleanup, and stale-closure pitfalls—not just when effects run.
useEffect synchronizes your component with external systems—fetch, subscriptions, DOM APIs—not "lifecycle replacement" only.
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal })
.then((r) => r.json())
.then(setData)
.catch((error) => {
if (error.name !== "AbortError") {
handleError(error);
}
});
return () => controller.abort(); // cleanup on dep change or unmount
}, [url]);| Pitfall | Fix |
|---|---|
| Missing deps | Include values used inside; or move stable logic out |
| Stale closure in effects | useEffectEvent for event-like logic that should see latest props/state without becoming a reactive dependency—or correct deps, not lint silencing |
| No cleanup | Leaks timers/subscriptions |
| Strict Mode double invoke (dev) | Effects must be idempotent; cleanup must work |
Prefer TanStack Query or framework data loaders over raw fetch effects for server data in 2026 interviews. In React 19.2, useEffectEvent separates event-like logic inside Effects from reactive dependencies—useful when an Effect should see the latest values without re-synchronizing for those values. Do not use it merely to silence dependency lint errors. Effect Events can only be called from Effects or other Effect Events—do not pass them to child components or call them from regular event handlers.
A strong answer is:
useEffectruns after React commits the update. I declare honest dependencies, clean up subscriptions and abort fetches, and useuseEffectEventin React 19.2 when Effect-triggered logic needs the latest props/state without becoming a dependency. I reach for query libraries instead of hand-rolled fetch effects when data is server-backed.
What are the Rules of Hooks?
What interviewers are testing: Whether you know why hook call order matters and when the React 19 use() API is an exception.
- Only call hooks at the top level — not inside loops, conditions, or nested functions
- Only call hooks from React functions — components or custom hooks
Why: React relies on call order to associate state with each hook instance.
React 19 exception: use() is a React API rather than a normal Hook. It may be called conditionally or in loops, although it still must be called while React renders a component or Hook.
Breaking rules causes "Rendered more hooks than previous render" bugs—impossible to debug casually.
Custom hooks must also follow these rules and name with use prefix.
A strong answer is:
Hooks run in a fixed order every render—I never call them conditionally except for
use(), which React documents as a special API, and I extract reusable logic into custom hooks instead of copying stateful patterns.
When do useCallback and useMemo help — and when are they premature optimization?
What interviewers are testing: Whether you justify memoization with measured re-render cost—not blanket useCallback on every handler.
| Hook | Caches |
|---|---|
useMemo |
Expensive computation result |
useCallback |
Stable function reference |
Helpful when:
- Passing callbacks to
React.memochildren that would re-render on reference change - Heavy derived data (large list filtering) proven slow in profiler
Not needed for every inline function—manual memoization has complexity and runtime overhead of its own, so it should solve an actual identity or computation problem.
const visible = useMemo(() => items.filter((i) => i.active), [items]);
const onSelect = useCallback((id) => setSelected(id), []);Interview trap: wrapping everything in useCallback without memoized children buys nothing.
The React Compiler can automatically memoize values, functions, and components where safe, reducing routine manual useMemo/useCallback/memo. Understand them anyway because existing codebases and library boundaries still rely on them—do not mechanically add manual memoization when the compiler/toolchain already handles it.
A strong answer is:
I use useMemo and useCallback when profiling shows wasted child renders or expensive derivations—not by default on every handler.
What is useRef used for?
What interviewers are testing: Whether you distinguish mutable non-rendering state from UI state and know when refs are appropriate for DOM access or imperative integration.
useRef holds a mutable box that persists across renders without triggering re-render when .current changes.
| Use | Example |
|---|---|
| DOM access | Focus input, measure element |
| Mutable imperative value | Timer ID, third-party instance |
| Latest-value escape hatch | Occasionally needed for imperative callbacks; prefer useEffectEvent for Effect Events |
const inputRef = useRef(null);
useEffect(() => inputRef.current?.focus(), []);Unlike state, updating ref.current does not schedule render.
A strong answer is:
I use refs for DOM nodes and mutable values that should survive renders without causing a render. If the value belongs in visible UI, it should normally be state instead.
When should you use useContext?
What interviewers are testing: Whether you know when Context subscriptions become too broad and how to split or memoize provider values.
Context shares values deep in the tree without prop drilling—theme, locale, auth snapshot.
| Good fit | Poor fit |
|---|---|
| Low-frequency updates | Frequently changing context values can cause broad updates across subscribed consumers, especially when one large context combines unrelated state |
| Theme, i18n, auth user | Entire app state store |
Pattern:
const ThemeContext = createContext("light");
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}For complex client state, consider Zustand, Redux Toolkit, or colocated state + query library.
A strong answer is:
A provider value change updates components subscribed to that context, so I avoid one large frequently changing context and split concerns when needed.
What are custom hooks? Implement a useDebounce pattern.
What interviewers are testing: Whether you can implement a real custom Hook—not only a standalone debounce utility—and explain how it composes with effects.
Custom hooks extract stateful logic reusable across components—they must follow Rules of Hooks.
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// Usage
const debouncedQuery = useDebounce(query, 300);Pair debounced values with fetch effects or query libraries—cleanup clears the timeout on unmount or when value changes.
A strong answer is:
Custom hooks share stateful behavior—I extract debounce, fetch, and media-query logic into
use*functions so components stay declarative.
State management and data fetching
Local state vs global state vs server state?
What interviewers are testing: whether you keep UI state local, lift only when siblings need it, and put server cache in TanStack Query—not Redux by default.
| Category | Examples | Tooling |
|---|---|---|
| Local | Form field, modal open | useState |
| Shared client | Wizard steps, UI preferences | Context, Zustand, Redux |
| Server | API records, pagination | TanStack Query, SWR, RSC |
Colocation principle: keep state as low as possible until multiple distant components need it.
Server state is async, cached, and shared—different from client UI toggles. Do not copy server lists into Redux by default in 2026 greenfield apps.
A strong answer is:
Local state for UI, global client libraries only when prop drilling hurts, and dedicated server-state tools for API data with cache and invalidation.
Why use TanStack Query instead of useEffect for fetching?
What interviewers are testing: Whether you justify TanStack Query for server-state caching and when raw useEffect fetch is still appropriate.
useEffect fetch |
TanStack Query |
|---|---|
| Manual loading/error flags | Built-in states |
| No cache deduplication | Shared cache per query key |
| Refetch logic reinvented | Stale time, retry, invalidation |
| Race conditions manual | Query-key-based cache sharing and request deduplication |
const { data, isLoading, error } = useQuery({
queryKey: ["orders", page],
queryFn: () => fetchOrders(page),
});Interviewers want you to mention query keys, stale-while-revalidate, and mutations with optimistic updates. TanStack Query is not mandatory for every fetch—the decision depends on server-state complexity and framework architecture.
A strong answer is:
TanStack Query handles caching, deduplication, and refetch policies for server state—I use effects for true externals like subscriptions, not routine GET requests.
When is Redux Toolkit still justified?
What interviewers are testing: Whether you know when shared client state complexity justifies Redux Toolkit over lighter stores and query libraries.
Redux shines when:
- Many features read/write shared client state with traceable updates
- You need devtools, time-travel debugging, middleware
- Complex cross-feature workflows (multi-step wizards, offline sync)
Often overkill for apps where server state dominates—Query + light Context/Zustand covers many products.
Redux Toolkit reduces boilerplate with slices and createAsyncThunk—know it even if you prefer simpler stores.
A strong answer is:
I reach for Redux when client state is complex and many modules need predictable updates; otherwise Query plus minimal local/global state is enough.
What is lifting state up?
What interviewers are testing: Whether you know when to lift shared state to a common ancestor versus URL or store patterns.
When two siblings need the same data, move state to their common parent and pass props down + callbacks up.
Parent (owns `filter`)
/ \
List FilterBarAlternative: shared store or URL search params for bookmarkable filter state.
A strong answer is:
I lift state to the lowest common ancestor when siblings must stay in sync, or use URL/query state when users should share or bookmark it.
Composition vs inheritance in React?
What interviewers are testing: Whether you favor composition—children, render props, and hooks—over class inheritance for reuse.
React favors composition—pass children or render props instead of deep class hierarchies.
function Card({ title, children }) {
return (
<section>
<h2>{title}</h2>
{children}
</section>
);
}Patterns: compound components, slots, higher-order components (less common now), custom hooks (preferred reuse in hooks era).
A strong answer is:
I compose behavior with children and hooks rather than subclassing components—composition keeps trees flexible and types clearer.
Performance, rendering, and lists
What does React.memo do?
What interviewers are testing: Whether you understand prop comparison and can justify memoization based on measured render cost rather than applying it everywhere.
React.memo wraps a component to skip re-render when each prop compares equal to its previous value using Object.is, unless a custom comparator is supplied.
memo only optimizes re-renders caused by unchanged parent props; the component still renders when its own state or a Context it consumes changes.
Requires stable props—inline object/function props defeat memo unless parent uses useMemo/useCallback.
Use when profiler shows expensive pure presentational children re-rendering often.
A strong answer is:
React.memoskips re-render when props are unchanged byObject.is—I pair it with stable callbacks only after profiling proves child render cost matters.
Why are keys important in lists?
What interviewers are testing: whether you use stable unique keys so React reconciles lists without remounting or state loss.
Keys help React identify which items changed, were added, or removed.
| Key choice | Result |
|---|---|
| Stable unique id | Correct reuse of component state |
| Array index | Breaks on reorder/insert—avoid when list mutates |
Wrong keys cause state bugs (wrong row stays checked) and inefficient DOM updates.
A key must be stable and unique among its siblings—it does not need to be globally unique across the application.
A strong answer is:
Keys must be stable per entity— I use database ids, not array indexes, for dynamic lists so React matches the right row across renders.
What causes unnecessary re-renders and how do you debug them?
What interviewers are testing: Whether you can trace re-render causes to state placement, context, and unstable identities at memo or effect boundaries.
Common causes:
| Cause | Fix |
|---|---|
| Parent re-rendered | memo, split state down |
| Unstable object/function identity | Matters at memo/effect boundaries; simplify props or stabilize only when needed |
| Context value recreated | Memoize provider value |
| Global store too coarse | Selectors, split contexts |
Tools: React DevTools Profiler, why-did-you-render (dev), logging render counts.
A strong answer is:
I profile first, then fix the actual source—unstable props, fat context, or state living too high—not blanket memo everywhere.
What is code splitting and lazy loading in React?
What interviewers are testing: Whether you understand bundle splitting with lazy() and when the lazy component is actually rendered—not only how to import it.
Code splitting loads JavaScript chunks on demand—smaller initial bundle.
const AdminPanel = lazy(() => import("./AdminPanel"));
function App() {
const [showAdmin, setShowAdmin] = useState(false);
return (
<>
<button onClick={() => setShowAdmin(true)}>Open admin</button>
{showAdmin && (
<Suspense fallback={<Spinner />}>
<AdminPanel />
</Suspense>
)}
</>
);
}lazy() splits the component into another bundle; actual deferral depends on when that lazy component is rendered. Route-based splitting (React Router, Next.js) is the most common production pattern.
A strong answer is:
I lazy-load heavy routes and admin surfaces behind Suspense so first paint ships only what most users need.
Why does useEffect run twice in development?
What interviewers are testing: Whether you know Strict Mode's development-only extra Effect cycle at mount and why cleanup must be correct.
React Strict Mode in development intentionally stress-tests components and effects:
- components re-render an extra time in development
- In development Strict Mode, React runs an extra setup→cleanup→setup cycle when an Effect mounts to expose missing cleanup bugs
- ref callbacks are re-run with an extra setup/cleanup cycle in development
These extra checks are development-only. Normal production effects still rerun whenever their dependencies change.
Your effect cleanup must abort fetches and clear timers—double invoke proves that works.
A strong answer is:
Strict Mode stress-tests effects and cleanup in dev on purpose—I write idempotent effects with proper cleanup so production behavior stays reliable when dependencies change.
Routing, forms, errors, and testing
How does client-side routing work with React Router?
What interviewers are testing: Whether you can explain client-side routing, nested routes, and route-level data loading in modern React Router.
React Router maps URL paths to component trees without full page reload.
| Concept | Role |
|---|---|
<Routes> / <Route> |
Path → element |
<Link> |
Declarative navigation |
useParams |
Dynamic segments (/users/:id) |
useSearchParams |
Query strings |
| Loaders/actions | Route-level data loading and mutations in data-router/framework modes |
Use route guards or loaders to redirect unauthenticated users for UX, but enforce authentication and authorization again on the server/API—the client-side route guard is not a security boundary.
Pair with full stack interviews for end-to-end auth flows.
A strong answer is:
React Router keeps URL and UI in sync on the client—I use nested routes, loaders where appropriate, and guarded routes for auth.
What are error boundaries?
What interviewers are testing: Whether you know what error boundaries catch in render—and what they do not catch in events or async code.
Error boundaries catch render errors in child tree and show fallback UI—they must be class components (still in 2026) or framework equivalents.
They do not catch:
- Event handler errors (use try/catch)
- Async errors outside render
- Errors in the boundary itself
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() { return { hasError: true }; }
componentDidCatch(error, info) { log(error, info); }
render() {
return this.state.hasError ? <Fallback /> : this.props.children;
}
}A strong answer is:
Error boundaries isolate render failures so the whole app does not white-screen—I log to monitoring and still handle event and async errors separately.
How do React 19 Actions improve forms?
What interviewers are testing: Whether you understand how Actions integrate async mutations with transitions—not automatic error handling for every thrown failure.
Actions are async functions passed to <form action={submitAction}> that integrate async updates with React's transition model.
Related APIs:
| API | Role |
|---|---|
useActionState |
Action result state, dispatch, and pending status |
useFormStatus |
Pending state in child buttons |
useOptimistic |
Instant UI while mutation completes |
function OrderForm() {
const [state, submitAction, isPending] = useActionState(saveOrder, {
ok: false,
});
return (
<form action={submitAction}>
{/* fields */}
<button disabled={isPending}>Save</button>
</form>
);
}
async function saveOrder(prevState, formData) {
// validate and persist
return { ok: true };
}A function passed directly to <form action={saveOrder}> receives formData as its single argument—the (prevState, formData) signature is for actions wired through useActionState.
Actions integrate async mutations with React's transition model. useActionState can expose action result state and pending status, useFormStatus exposes form submission status, and useOptimistic supports optimistic UI. Thrown errors still interact with error handling and boundaries.
React Actions are the broader React form/action model. "use server" belongs to frameworks/environments that support Server Functions (for example Next.js); it is not required for every React Action.
Even without Next.js, interviewers expect you to know Actions reduce hand-rolled loading flags.
A strong answer is:
React 19 Actions integrate async mutations with forms and transitions, reducing hand-rolled pending-state orchestration. I use
useActionState,useFormStatus, anduseOptimisticwhere they simplify the mutation flow.
What does <Activity /> do in React 19.2?
What interviewers are testing: Whether you understand visible vs hidden UI modes, preserved state, Effect lifecycle, and update prioritization—not as a generic layout wrapper.
<Activity /> (React 19.2) controls whether a subtree is visible or hidden:
| Mode | Behavior |
|---|---|
| visible | Normal rendering and updates |
| hidden | UI is hidden, state is preserved, Effects are unmounted, and updates are deprioritized |
Useful for preserving navigation or tab state, pre-rendering likely next UI, or keeping expensive subtrees warm without treating them as actively visible.
A strong answer is:
<Activity />lets me hide UI while preserving state—hidden mode unmounts Effects and deprioritizes updates, which is useful for tabs or pre-rendered panels without losing user progress.
How do you test React components?
What interviewers are testing: Whether you test behavior through accessible queries and realistic user interactions—not implementation details.
React Testing Library encourages tests that resemble user behavior:
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
test("increments counter", async () => {
const user = userEvent.setup();
render(<Counter />);
await user.click(screen.getByRole("button", { name: /increment/i }));
expect(screen.getByText("1")).toBeInTheDocument();
});Use fireEvent only when you need lower-level event dispatch.
| Layer | Tool |
|---|---|
| Unit | RTL + Vitest/Jest |
| Integration | MSW for API mocks |
| E2E | Playwright, Cypress |
Test behavior and accessibility roles—not implementation details like internal state variable names.
A strong answer is:
I test what users see and do with Testing Library, mock APIs with MSW, and reserve E2E for critical flows like checkout or login.
What React accessibility practices do interviews expect?
What interviewers are testing: Whether you prioritize semantics, labels, keyboard behavior, and focus management—not ARIA alone.
| Practice | Detail |
|---|---|
| Semantic HTML | button vs div onClick |
| Labels | htmlFor + id on inputs |
| Keyboard | Focus trap in modals, Escape to close |
| ARIA sparingly | Fix semantics first |
| Live regions | Announce async updates |
React does not fix a11y automatically—see front end interviews for broader WCAG depth.
A strong answer is:
I use semantic elements, label every control, manage focus in dialogs, and test with keyboard and screen reader checks—not bolt-on ARIA only.
React 18, React 19, and Server Components
What are concurrent features in React 18?
What interviewers are testing: Whether you understand urgent vs non-urgent updates and do not put controlled text input values inside transitions.
Concurrent rendering lets React interrupt low-priority updates to keep UI responsive.
| API | Use |
|---|---|
useTransition |
Mark non-urgent state updates (filter large list) |
useDeferredValue |
Defer rendering expensive derived value |
Suspense |
Wait for lazy code or async data with fallback |
const [text, setText] = useState("");
const [filter, setFilter] = useState("");
const [, startTransition] = useTransition();
function handleChange(e) {
const next = e.target.value;
setText(next); // urgent: controls input
startTransition(() => {
setFilter(next); // non-urgent: expensive results
});
}Transitions cannot control text inputs—keep the input value in urgent state and transition downstream work.
A strong answer is:
Concurrent features prioritize urgent UI like typing over heavy re-renders—I keep controlled inputs urgent and use transitions or
useDeferredValuefor expensive downstream updates.
What are React Server Components (RSC)?
What interviewers are testing: Whether you understand the server/client boundary and that Client Components in the tree still ship JavaScript.
Server Components run only on the server—their implementation does not ship to the browser.
| Server Component | Client Component ("use client") |
|---|---|
| Component implementation stays on server | Component implementation runs in browser |
| Can access server resources directly | Can use state, browser APIs, event handlers |
| Adds no client JS for the Server Component itself | Contributes to client bundle |
Not the same as SSR: SSR still hydrates client components; RSC sends rendered output without hydrating Server Component code.
Popular in Next.js App Router—know the boundary interview answer even if your team uses Vite SPA.
A strong answer is:
Server Component code stays on the server and can access server-side data directly; interactive islands cross the boundary into Client Components and ship their own JavaScript.
What is the use() API in React 19?
What interviewers are testing: Whether you know use() is not a Hook, can be conditional, and works with framework-created Suspense-compatible Promises.
use() reads a Promise or Context during render—despite its name, it is not a Hook and can be called conditionally (unlike other hooks).
Integrates with Suspense—component suspends until Promise resolves.
function Comments({ commentsPromise }) {
const comments = use(commentsPromise);
return comments.map((c) => <p key={c.id}>{c.text}</p>);
}In Client Components, do not create a new uncached Promise during render and immediately pass it to use()—framework/server-created or cached Suspense-compatible Promises are the usual pattern. use(context) can be conditional, but current React docs state reading context with use(context) is not supported in Server Components.
Prefer framework data patterns you can explain—RSC, Query, or use() with Suspense boundaries.
A strong answer is:
use()is a React API that reads promises or context during render with Suspense—it can be conditional unlike Hooks, but I rely on framework-created promises rather than ad hoc render-time fetches.
SSR vs CSR vs SSG — when do you use each?
What interviewers are testing: whether you pick SSR for SEO and first paint, CSR for highly interactive apps, and SSG for mostly static content.
| Model | When |
|---|---|
| CSR | Dashboards behind auth, highly interactive SPA |
| SSR | SEO pages, fast first paint with dynamic data |
| SSG | Marketing docs, blogs with build-time content |
| ISR | Mix—static with periodic revalidation (Next.js) |
Hydration mismatch is a common production bug—server HTML must match client first render.
A strong answer is:
I pick rendering mode by SEO, personalization, and interactivity—SSG/SSR for public content, CSR or hybrid for authenticated apps with heavy client state.
What is React Compiler?
What interviewers are testing: Whether you understand what React Compiler 1.0 automates and why manual memoization knowledge still matters.
The React Compiler reached 1.0 in October 2025 and automatically memoizes components and values when safe—reducing manual useMemo/useCallback/memo.
Interview angle: compiler does not remove need to understand rendering—it optimizes proven patterns.
Teams enable gradually with lint rules and compatibility checks.
A strong answer is:
The React Compiler auto-memoizes where safe—I still understand render identity and dependencies because compilation can be incrementally adopted, and existing uncompiled code still uses the same React semantics.
Patterns, architecture, and coding scenarios
How do you avoid prop drilling?
What interviewers are testing: Whether you try composition and colocation before reaching for Context or a global store.
Options:
| Approach | When |
|---|---|
| Composition | Pass children or render props |
| Context | Wide low-churn values |
| Colocation | Split components so intermediates disappear |
| Client store | Many distant consumers |
Do not reach for global state before trying composition and colocation.
A strong answer is:
I colocate state and compose children first; Context or a small store only when many distant components need the same client data.
What are React portals?
What interviewers are testing: Whether you know portals escape DOM layout constraints while remaining in the same React tree.
Portals render children into a different DOM node—typically document.body for modals and tooltips. They are common for modals and overlays because they can escape DOM layout/stacking constraints while remaining in the same React tree; accessibility still requires correct dialog semantics and focus management.
createPortal(<Modal />, document.getElementById("modal-root"));Event bubbling still follows React tree (not DOM tree)—important for delegation tests.
A strong answer is:
Portals render UI elsewhere in the DOM while keeping React event bubbling logical—they escape layout and stacking constraints, but accessibility still requires correct dialog semantics and focus management.
Why must React state updates be immutable?
What interviewers are testing: Whether you treat state as an immutable snapshot and understand why mutation breaks reconciliation and memoization.
React state should be treated as an immutable snapshot. Mutating an existing object and passing the same reference back can prevent an expected update and also breaks assumptions used by memoization and concurrent rendering.
// Wrong — mutates
state.push(item);
// Right — new reference
setState([...state, item]);
setState({ ...state, count: state.count + 1 });A strong answer is:
I treat state as an immutable snapshot and create new objects or arrays for updates. Mutating old state can break update detection, memoization, and assumptions used by concurrent rendering.
How do synthetic events work in React?
What interviewers are testing: Whether you understand React's event abstraction, root-level delegation, and how modern SyntheticEvents differ from the old pooled-event model.
React wraps browser events in SyntheticEvent for cross-browser normalization.
| Detail | Interview note |
|---|---|
| Delegation | React 17+ attaches to root container |
preventDefault |
Still explicit for forms/links |
| No pooling (modern) | React DOM no longer pools event objects; event.persist() is unnecessary on the web |
Prefer controlled patterns over reading DOM after async without storing values.
A strong answer is:
SyntheticEvent gives React a consistent event interface while preserving browser event access through
nativeEvent. In modern React DOM, event objects are no longer pooled; I mainly care about propagation, default prevention, and React's delegated event model.
React coding interview scenarios
Coding scenario: Build a todo list — what do interviewers evaluate?
What interviewers are testing: Whether you can structure state, keys, immutability, and accessibility for a small list feature under time pressure.
Expected features: add, toggle complete, filter (all/active/done), delete.
| Criteria | Strong signal |
|---|---|
| State shape | Array of { id, text, done } not parallel arrays |
| Keys | Stable id, not index |
| Immutability | Map/filter for updates |
| Accessibility | Labels, button types, list semantics |
| Edge cases | Empty state, duplicate submit |
function todosReducer(state, action) {
switch (action.type) {
case "add":
return [...state, { id: crypto.randomUUID(), text: action.text, done: false }];
case "toggle":
return state.map((t) => (t.id === action.id ? { ...t, done: !t.done } : t));
default:
return state;
}
}Mention useReducer when transitions multiply—shows structure for growing state machines.
A strong answer is:
I model todos as an immutable array with stable ids, use reducer or useState clearly, filter without mutating, and wire accessible controls—not a quick DOM hack.
Coding scenario: Search with API — debounce, abort, and loading states.
What interviewers are testing: Whether you can debounce input, abort stale requests, and avoid loading/error races—not only set state after unmount.
Checklist:
- Controlled input
- Debounce query (300–400 ms)
- AbortController cancel stale requests
- Loading / error / empty UI states
- Do not set state after unmount or after a superseded request
useEffect(() => {
if (!debouncedQuery) return;
const controller = new AbortController();
setLoading(true);
setError(null);
fetch(`/api/search?q=${debouncedQuery}`, { signal: controller.signal })
.then((r) => {
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return r.json();
})
.then(setResults)
.catch((e) => { if (e.name !== "AbortError") setError(e); })
.finally(() => {
if (!controller.signal.aborted) {
setLoading(false);
}
});
return () => controller.abort();
}, [debouncedQuery]);Senior mention: A server-state library can centralize query caching, cancellation signals, previous-data behavior, retries, and request status.
A strong answer is:
I debounce input, abort in-flight fetches on change, guard loading state against aborted requests, and render loading and error explicitly—or use a query library if the stack allows.
Coding scenario: Fix a component that loops infinitely — common causes?
What interviewers are testing: Whether you can diagnose self-triggering effects from dependency arrays and unstable identities.
| Cause | Symptom |
|---|---|
| Effect with no dependency array updates state | Repeats after every render |
| Object/function dependency recreated each render | Effect repeatedly re-runs |
| Effect updates state included in its own dependencies | Self-triggering loop |
Fix patterns:
- Narrow dependencies to primitives
- Functional updates:
setItems((prev) => ...) - Move object creation outside effect or memoize
- Do not derive state from state in effect when render can compute it
A strong answer is:
Infinite loops usually mean an effect writes state that retriggers itself—I fix dependency arrays, derive values in render instead of effects, and use functional updates.
Scenario: Users report a slow React dashboard — how do you investigate?
What interviewers are testing: Whether you start from user-visible impact and classify the bottleneck before jumping to React Profiler—rendering is only one possible cause.
| Step | Action |
|---|---|
| 1 | Reproduce and classify: startup/LCP, interaction/INP, navigation, network, or render |
| 2 | Check field/production telemetry if available |
| 3 | Inspect network waterfall and API timings |
| 4 | Use React Profiler when rendering is implicated |
| 5 | Check large lists, wide Context updates, expensive computations |
| 6 | Check bundle size and code splitting |
| 7 | Fix highest-impact bottleneck and re-measure |
Connect to front end performance topics (LCP, INP).
A strong answer is:
I reproduce the symptom, check real-user metrics and network first, then profile renders if UI work is implicated—I fix the biggest measurable bottleneck before micro-optimizing hooks.
Final React interview checklist
- Explain Virtual DOM, keys, and one-way data flow
-
useEffectdeps, cleanup, Strict Mode extra mount cycle in dev -
useMemo/useCallbackonly with justification - Server vs Client Components and when you would use each
- TanStack Query vs raw fetch
- Timed todo and debounced search coding reps
- Error boundaries and testing with RTL
- One performance and one production bug STAR story
- Front end developer interview questions for broader UI fundamentals
- Full stack developer interview questions if the role is end-to-end
Pattern cheat sheet (quick reference)
| Need | React starting point |
|---|---|
| Local UI state | useState / useReducer |
| Side effects / subscriptions | useEffect + cleanup |
| Server data | TanStack Query / RSC |
| Avoid list bugs | Stable key={item.id} |
| Expensive child renders | memo + stable props (after profile) |
| Slow typing on filter | useTransition |
| Heavy route | lazy + Suspense |
| Forms (React 19) | Actions + useActionState |
| Global theme/auth | Context (low churn) |
| Modal overlay | Portal + focus trap |
| Tests | Testing Library + MSW |
References
Official React documentation
- React documentation
- Adding interactivity
- Hooks reference
- Server Components
- React 19 release notes
- React 19.2 release notes
- React Compiler 1.0
Summary
React interviews in 2026 still start with fundamentals—components, JSX, props versus state, controlled inputs, and the Rules of Hooks—but panels quickly move to whether you can reason about rendering and data under real constraints. Expect hooks depth (useState snapshots, useEffect cleanup, custom hooks like useDebounce), state layering (local, Context, TanStack Query, Redux when justified), and performance judgment (memo, keys, transitions without breaking controlled inputs).
Mid-level loops add routing, error boundaries, Testing Library habits, React 19 Actions, and the modern bridge topics: Server Components, use(), Suspense, concurrent updates, React Compiler 1.0, and React 19.2 features such as useEffectEvent and <Activity />. Coding rounds reward immutable state, stable keys, debounced search with abort and loading guards, and calm debugging of self-triggering effects.
Use the prep sections and final checklist to rehearse aloud. When the role expects Fiber-level architecture, hydration, and production performance scenarios, continue with the experienced React article linked above.

