Skip to main content

Amazon Interview React Interview Questions

Curated Amazon Interview-level React interview questions for developers targeting amazon interview positions. 155 questions available.

Last updated:

React Interview Questions & Answers

Skip to Questions

Welcome to our comprehensive collection of React interview questions and answers. This page contains expertly curated interview questions covering all aspects of React, from fundamental concepts to advanced topics. Whether you're preparing for an entry-level position or a senior role, you'll find questions tailored to your experience level.

Our React interview questions are designed to help you:

  • Understand core concepts and best practices in React
  • Prepare for technical interviews at all experience levels
  • Master both theoretical knowledge and practical application
  • Build confidence for your next React interview

Each question includes detailed answers and explanations to help you understand not just what the answer is, but why it's correct. We cover topics ranging from basic React concepts to advanced scenarios that you might encounter in senior-level interviews.

Use the filters below to find questions by difficulty level (Entry, Junior, Mid, Senior, Expert) or focus specifically on code challenges. Each question is carefully crafted to reflect real-world interview scenarios you'll encounter at top tech companies, startups, and MNCs.

Questions

155 questions
Q1:

What problem does React solve compared to directly manipulating the DOM?

Entry

Answer

React uses a virtual DOM to batch updates and apply only necessary changes to the real DOM. This reduces reflow and repaint costs, making UI updates efficient and predictable.
Quick Summary: Direct DOM manipulation is slow and error-prone — every change triggers browser reflows and repaints. React introduces a virtual DOM: you describe what the UI should look like, React figures out the minimal set of real DOM updates needed. Your code stays clean; React handles the expensive DOM work efficiently.
Q2:

What is JSX and why do we use it in React?

Entry

Answer

JSX is a JavaScript syntax extension that allows writing HTML-like code within JavaScript. It improves readability and compiles into React.createElement() calls during build.
Quick Summary: JSX is a syntax extension that lets you write HTML-like markup inside JavaScript. It gets compiled to React.createElement() calls. It's not required but makes component structure readable and obvious — you see the tree structure directly. JSX also catches errors at compile time that string-based templates miss.
Q3:

Why must React components start with a capital letter?

Entry

Answer

React treats lowercase tags as built-in HTML elements. Uppercase names indicate custom components so React can instantiate them correctly.
Quick Summary: React uses the capitalization to distinguish between built-in HTML elements (lowercase, like div or span) and custom components (capitalized, like MyButton). When React sees a lowercase tag, it renders the HTML element. When it sees uppercase, it looks for a component function or class with that name to call.
Q4:

What is the purpose of the createRoot API introduced in React 18?

Entry

Answer

createRoot enables concurrent rendering, allowing React to pause, resume, or interrupt rendering to improve UI responsiveness.
Quick Summary: createRoot replaces ReactDOM.render() and enables all React 18 features including concurrent rendering. You call createRoot(domNode) once to set up the root, then .render() to display your component. The split allows React to manage multiple roots independently and enables concurrent features like Suspense and transitions.
Q5:

What is the difference between a Component and an Element in React?

Entry

Answer

A component is a function or class defining UI logic. An element is the object returned by that component describing what to render.
Quick Summary: A React Element is a plain object describing what to render — like the output of JSX: { type: 'div', props: { children: 'Hello' } }. A Component is a function or class that returns elements. Components are the blueprint; elements are the instances produced each render. Elements are immutable snapshots; components are reusable factories.
Q6:

What is the use of React Fragment?

Entry

Answer

Fragments (<> ) let you return multiple elements without adding extra DOM nodes, keeping layouts cleaner.
Quick Summary: Fragment lets you return multiple elements from a component without adding an extra DOM node. Instead of wrapping everything in a div (which adds unnecessary markup), you use or the shorthand <>.... This keeps the DOM clean and avoids styling issues caused by extra wrapper elements.
Q7:

Why do we use keys in lists?

Entry

Answer

Keys help React track which list items changed, were added, or removed, enabling efficient virtual DOM reconciliation.
Quick Summary: Keys help React identify which items in a list changed, were added, or were removed between renders. Without keys, React can't tell items apart and may reuse the wrong DOM node — causing incorrect rendering, lost input state, and animation bugs. Keys must be stable, unique identifiers for each item.
Q8:

What happens if we use the array index as a key?

Entry

Answer

Using array indexes can cause React to reuse incorrect DOM nodes, leading to bugs like wrong input values or lost component state during reorder.
Quick Summary: If items are reordered or inserted, the index shifts — React sees the key change and remounts the component, losing its state. For a list of inputs, inserting a new item at the top shifts every index, causing React to treat existing items as new ones. Use a stable unique ID (like a database ID) instead.
Q9:

What is the difference between props and state?

Entry

Answer

Props are read-only inputs passed from parent components, while state is internal mutable data managed by the component.
Quick Summary: Props are read-only inputs passed from parent to child — the parent controls them. State is internal data owned and managed by the component itself. Props flow down; state triggers re-renders when it changes. A component can't modify its own props, but it can update its own state with a setter function.
Q10:

Can a component modify its own props?

Entry

Answer

No. Props are immutable and controlled by the parent. Changing them breaks unidirectional data flow.
Quick Summary: No. Props are read-only by design — a component receives them from its parent and must use them as-is. Modifying props would break the data flow and make components unpredictable. If a component needs to change data, it either calls a callback prop (to let the parent update state) or manages that data in its own state.
Q11:

What does useState() return?

Entry

Answer

useState returns an array with the current state value and a function to update that state.
Quick Summary: useState returns an array with two things: the current state value and a setter function. const [count, setCount] = useState(0) — count holds the current value, setCount triggers a re-render with the new value. The initial value (0 here) is only used on the first render.
Q12:

Why doesn’t updating state directly trigger a re-render?

Entry

Answer

React re-renders only when the state updater function is called. Direct mutation does not notify React.
Quick Summary: React tracks state through its setter function, not the object itself. When you do state.count = 5 directly, React never knows anything changed and doesn't schedule a re-render. You must call setState(newValue) — that's what signals React to diff the new state against the old and update the UI.
Q13:

What is the purpose of useEffect?

Entry

Answer

useEffect runs side effects after rendering, such as API calls, subscriptions, timers, or DOM manipulation.
Quick Summary: useEffect lets you run side effects after a component renders — data fetching, subscriptions, DOM manipulation. It runs after the browser paints, keeping rendering fast. The dependency array controls when it re-runs. A cleanup function lets you cancel subscriptions or timers when the component unmounts.
Q14:

What happens if you forget dependencies in useEffect?

Entry

Answer

The effect runs after every render, potentially causing infinite loops or unnecessary API requests.
Quick Summary: Without all dependencies listed, the effect captures stale values from its first render (a stale closure). The effect runs but uses old data — leading to bugs that are hard to trace. ESLint's exhaustive-deps rule catches this. In React 18+, running effects twice in Strict Mode also surfaces these issues.
Q15:

What is controlled vs uncontrolled component in forms?

Entry

Answer

Controlled components store form values in React state. Uncontrolled components store input values in the DOM and use refs to access them.
Quick Summary: Controlled: form input value is driven by React state — React owns the value, every keystroke goes through state. Uncontrolled: the DOM owns the value, accessed via a ref. Controlled gives you full control and validation at every change. Uncontrolled is simpler but you lose the ability to sync or validate on every input.
Q16:

What is React Strict Mode and why is it useful?

Entry

Answer

Strict Mode highlights potential issues by intentionally double-running certain logic in development to detect unsafe patterns.
Quick Summary: Strict Mode activates extra development-only checks: it renders components twice to catch side effects in the render phase, double-fires effects to detect missing cleanup, and warns about deprecated APIs. None of this affects production. It's a great way to catch subtle bugs early without any runtime cost.
Q17:

What is Concurrent Rendering in React 18?

Entry

Answer

Concurrent Rendering allows React to pause, resume, interrupt, and prioritize UI rendering tasks for better responsiveness.
Quick Summary: Concurrent Rendering lets React interrupt, pause, and resume rendering work. Instead of blocking the main thread until a render completes, React can yield to higher-priority updates (like user input) mid-render. This makes apps feel more responsive — you can type in an input while React renders a heavy list in the background.
Q18:

What is useId introduced in React 18?

Entry

Answer

useId generates unique, stable IDs used for accessibility attributes and prevents hydration mismatches in SSR.
Quick Summary: useId generates a stable, unique ID that's consistent between server and client renders — preventing hydration mismatches. Useful for accessibility attributes like aria-labelledby where you need to link elements by ID. Unlike random IDs or incrementing counters, useId works correctly with SSR and concurrent rendering.
Q19:

What is the difference between useEffect and useLayoutEffect?

Entry

Answer

useEffect runs after the browser paints. useLayoutEffect runs before paint and is used for layout measurements.
Quick Summary: Both run after render, but at different times. useLayoutEffect fires synchronously after DOM mutations but before the browser paints — use it when you need to measure or adjust the DOM (like reading element size) before the user sees anything. useEffect fires after painting — use it for async operations and subscriptions.
Q20:

What are React Server Components?

Entry

Answer

Server Components run on the server, fetch data directly, and send lightweight results to the client, reducing bundle size and improving performance.
Quick Summary: React Server Components render on the server and send HTML (or serialized component tree) to the client — zero client-side JavaScript for those components. They can access databases and file systems directly, keep sensitive logic server-side, and reduce the JavaScript bundle size. Client components handle interactivity.
Q21:

How does React reconcile two virtual DOM trees during re-rendering?

Junior

Answer

React uses its diffing algorithm to compare the previous and next virtual DOM nodes. It reuses elements with the same type and key while replacing mismatches, ensuring minimal DOM operations.
Quick Summary: React's diffing algorithm compares two virtual DOM trees top-down. Elements of different types → full subtree replacement. Same type → compare props and update changed ones. Keys in lists → identify which items moved, were added, or removed. This O(n) heuristic is fast enough for most real-world UIs.
Q22:

Why is the render process pure but the commit phase is not in React?

Junior

Answer

The render phase only calculates changes and contains no side effects, making it pure. The commit phase applies changes to the DOM, causing side effects and making it impure.
Quick Summary: The render phase is pure — React may run it multiple times, discard results, or run it in parallel. No DOM mutations happen here. The commit phase is impure — React applies all DOM changes in one go. This two-phase design lets React interrupt rendering safely while guaranteeing that DOM updates are atomic and consistent.
Q23:

What problem do React Server Components solve?

Junior

Answer

They reduce client bundle size by performing data fetching and heavy computation on the server and sending lightweight serialized output to the client.
Quick Summary: Server Components eliminate the need to fetch data on the client and ship that data-fetching code to the browser. Data is fetched on the server, close to the database, and only the rendered output goes to the client. This reduces bundle size, eliminates client-server waterfalls, and keeps API keys and DB connections server-side.
Q24:

Why is data fetching in useEffect considered an anti-pattern in React 18+?

Junior

Answer

Fetching in useEffect runs after rendering, causing UI flicker. Modern React encourages server components or framework-level data loading.
Quick Summary: useEffect data fetching creates a client-side waterfall: render → useEffect fires → fetch → re-render. In React 18+, the preferred pattern is fetching in Server Components (zero client cost), using data-fetching libraries like SWR or React Query, or using the new use hook. useEffect for fetching is also problematic in Strict Mode's double-fire behavior.
Q25:

What is the difference between batching in React 17 and React 18?

Junior

Answer

React 17 batched updates only inside React events. React 18 batches updates automatically in async operations like promises and timeouts.
Quick Summary: React 17 only batched state updates inside event handlers — updates in setTimeout or promises caused separate re-renders. React 18 introduced automatic batching: all state updates (in any context — timeouts, promises, native events) are batched together into one re-render. Fewer re-renders, better performance by default.
Q26:

Why does React warn when state is updated during rendering?

Junior

Answer

Updating state during render breaks render purity and creates infinite re-render loops.
Quick Summary: Updating state during rendering creates an infinite loop or at least unpredictable behavior — the render triggers a state update which triggers another render. React detects this pattern and warns because the render function must be a pure, side-effect-free function. State updates belong in event handlers or effects, not mid-render.
Q27:

What is the purpose of the useTransition hook?

Junior

Answer

useTransition marks certain state updates as non-urgent, keeping the UI responsive while React processes expensive updates in the background.
Quick Summary: useTransition marks a state update as non-urgent — it tells React "this update can be interrupted if something more important comes in." React renders the current UI immediately and updates the transition in the background. While pending, isPending is true so you can show a loading indicator. Great for search, filtering, and navigation.
Q28:

How does React decide which components to re-render?

Junior

Answer

React re-renders a component when its state or props change or when its parent re-renders. Siblings do not re-render unless their props change.
Quick Summary: When state or props change, React re-renders that component and, by default, all its children — even if the children's props didn't change. React.memo, useMemo, and useCallback help break this chain by bailing out of re-renders when inputs haven't changed. Without memoization, re-renders cascade down the entire subtree.
Q29:

Why must React state remain immutable?

Junior

Answer

React detects state changes using reference equality. Mutating state directly keeps the same reference, preventing React from re-rendering.
Quick Summary: React uses object identity to detect changes. If you mutate an object in place (array.push, obj.x = 1), the reference doesn't change — React thinks nothing changed and skips re-rendering. Always create new objects/arrays for state updates so React sees a new reference and knows to update the UI.
Q30:

What happens when state setters run inside loops outside event handlers?

Junior

Answer

It can trigger multiple renders or infinite loops because render must stay pure and deterministic.
Quick Summary: React 18 automatically batches multiple state updates into one re-render, even in timeouts and promises. State setters inside loops or outside event handlers are batched and applied together at the end. The component re-renders once with the final accumulated state, not once per update.
Q31:

What is the Render Prop pattern?

Junior

Answer

It is a technique where a component receives a function as a child to dynamically render UI, enabling reusable logic.
Quick Summary: Render Props pass a function as a prop — the parent component calls it with data, and the child renders whatever the function returns. It's a pattern for sharing stateful logic between components without HOCs. Largely replaced by custom hooks, which are cleaner and less nested, but still useful in some library APIs.
Q32:

What problem does React Context solve?

Junior

Answer

Context avoids prop drilling by allowing components to access shared data without passing props through every level.
Quick Summary: Context provides a way to share values (theme, user, locale) across the component tree without prop drilling — passing props through every intermediate component. It's ideal for truly global data that many components need. For complex state management or high-frequency updates, Redux or Zustand are often better choices.
Q33:

How does React Context differ from Redux?

Junior

Answer

Context provides simple global state but triggers broad re-renders. Redux offers structured state management, middleware, and optimized performance.
Quick Summary: Context is built into React and great for low-frequency global data (theme, auth state). Redux is a separate library with a global store, strict action-based updates, middleware support, and powerful devtools. Context re-renders all consumers on any value change; Redux lets components subscribe to specific slices.
Q34:

What does useReducer help solve?

Junior

Answer

useReducer manages complex state logic with multiple transitions or nested updates, offering a structured alternative to multiple useState hooks.
Quick Summary: useReducer is better than useState when state has multiple sub-values that change together, or when the next state depends on complex logic based on the previous state. It centralizes state transition logic in one place (the reducer), making it easier to reason about, test, and debug — especially when state updates involve multiple fields.
Q35:

Why should objects or arrays not be placed directly in dependency arrays?

Junior

Answer

Objects and arrays create new references every render, causing effects to re-run unnecessarily.
Quick Summary: Object and array literals create a new reference every render — even if the contents are the same. In a dependency array, React uses Object.is() to compare — a new reference always triggers the effect or memo. Memoize objects and arrays with useMemo, or use primitive values in dependency arrays when possible.
Q36:

What is memoization in React and when is React.memo useful?

Junior

Answer

React.memo caches rendered output and prevents re-renders when props have not changed, improving performance for stable components.
Quick Summary: React.memo wraps a component and skips re-rendering if props haven't changed (shallow comparison). Useful when a child component is expensive to render and its parent re-renders frequently. Not a silver bullet — only effective when props are actually stable, and shallow comparison matches your needs.
Q37:

What is the difference between useMemo and useCallback?

Junior

Answer

useMemo memoizes computed values, while useCallback memoizes function references.
Quick Summary: useMemo caches the result of a computation — returns the same value until dependencies change. useCallback caches a function reference — returns the same function until dependencies change. Use useMemo for expensive calculations you don't want to recompute on every render. Use useCallback to stabilize functions passed as props to memoized children.
Q38:

Why is lifting state up used in React?

Junior

Answer

Shared state must be managed in a common parent to keep child components synchronized.
Quick Summary: When two sibling components need to share state, move that state up to their common parent. The parent manages the state and passes it down as props. This keeps state in sync without global stores. It's the fundamental React pattern for sharing data — keep state as close to where it's needed as possible, but no lower.
Q39:

What are controlled inputs and why can they hurt performance?

Junior

Answer

Controlled inputs update React state on each keystroke, causing re-renders that may slow down long forms.
Quick Summary: Controlled inputs re-render the component on every keystroke because each character change updates state. In large forms with many fields, this cascades re-renders across the form. Solutions: debounce state updates, split into smaller components with React.memo, or use uncontrolled inputs with refs for inputs that don't need real-time validation.
Q40:

What is Suspense and why was it introduced?

Junior

Answer

Suspense lets components wait for async resources with a fallback UI. It supports streaming and async rendering.
Quick Summary: Suspense lets components declare they're waiting for something (data, code) by throwing a Promise. React catches the throw, shows a fallback UI (like a spinner), and resumes rendering when the Promise resolves. This makes async loading declarative — you don't need loading state variables scattered through your code.
Q41:

How does Suspense differ in data fetching vs code splitting?

Junior

Answer

For code splitting it waits for dynamic imports; for data fetching it waits for a Promise to resolve.
Quick Summary: For code splitting (React.lazy), Suspense catches the lazy import promise and shows a fallback while the chunk loads. For data fetching, Suspense catches a data-fetching promise thrown by the component — but this requires a Suspense-compatible data library (like SWR, React Query, or Server Components). The mechanism is the same; the integration differs.
Q42:

What is hydration in React?

Junior

Answer

Hydration attaches event listeners and React behavior to server-rendered HTML to make it interactive.
Quick Summary: Hydration attaches React's event handlers to server-rendered HTML so the page becomes interactive. The server sends HTML (fast first paint), and the client-side React code runs and "takes over" the DOM without re-rendering everything. If the client render doesn't match the server HTML, React warns about a hydration mismatch.
Q43:

What is partial hydration?

Junior

Answer

Only selected components are hydrated, reducing JavaScript execution and improving performance.
Quick Summary: Partial hydration means only interactive parts of the page are hydrated — static content stays as plain HTML with no JavaScript attached. This reduces the client-side JS work needed to make the page interactive. React 18's selective hydration (in Suspense boundaries) is a form of partial hydration — interactive islands are hydrated on demand.
Q44:

How does React handle synthetic events?

Junior

Answer

React attaches a single root event listener and normalizes events across browsers for consistency and performance.
Quick Summary: React uses a Synthetic Event system that wraps browser native events in a cross-browser compatible object. In React 17+, events are attached to the root DOM container (not document), making React embeds easier to manage alongside other libraries. Synthetic events normalize browser differences and support event delegation efficiently.
Q45:

What is useDeferredValue used for?

Junior

Answer

It returns a deferred version of a rapidly changing value, allowing heavy UI updates to lag behind typing.
Quick Summary: useDeferredValue accepts a value and returns a deferred (potentially stale) version of it. React renders the UI with the immediate value first, then re-renders with the deferred value when it has time. Useful for search inputs — the text field updates instantly, but the expensive filtered list updates slightly later without blocking input.
Q46:

How does React 19 improve hydration?

Junior

Answer

React 19 supports partial hydration, reduces long tasks, and hydrates server components more efficiently.
Quick Summary: React 19 makes hydration more resilient — it can recover from mismatches between server HTML and client render (previously it would log a warning and re-render the entire component). It also improves streaming hydration performance and handles third-party script interference in the DOM better.
Q47:

What is useOptimistic in React 19?

Junior

Answer

useOptimistic enables optimistic UI updates before server confirmation, improving perceived performance.
Quick Summary: useOptimistic in React 19 lets you immediately show the expected result of an action before the server confirms it. The UI updates optimistically (appears instant), and if the server action fails, React reverts to the previous state. Replaces manual optimistic update patterns that required extra useState and error handling.
Q48:

What is the difference between the use hook and await in React 19?

Junior

Answer

The use hook unwraps promises directly during rendering and pauses rendering until resolved, working in server components.
Quick Summary: The use hook in React 19 is a new primitive that reads the value from a Promise or Context inside components (including conditionally inside loops). Unlike await which blocks, use integrates with Suspense — the component suspends while waiting, and resumes when the Promise resolves. Works in both Server and Client Components.
Q49:

Why shouldn’t data fetching occur in constructors or render methods?

Junior

Answer

Fetching causes side effects. Render and constructors must remain pure, so fetching should occur in effects or server loaders.
Quick Summary: Constructors and render methods run synchronously and block painting. Fetching data there delays the initial render. It also causes bugs in concurrent mode where React may run render multiple times. Data fetching belongs in effects, server-side data loaders, or Suspense-compatible libraries that integrate with React's rendering lifecycle.
Q50:

What is an error boundary?

Junior

Answer

An error boundary catches runtime errors in child components and displays a fallback UI instead of crashing the entire app.
Quick Summary: Error boundaries are class components that catch JavaScript errors thrown by their children during rendering, in lifecycle methods, or in constructors. They prevent the whole app from crashing — instead, they render a fallback UI. You can't use hooks for this; class components with componentDidCatch are required.
Q51:

Why shouldn’t you mutate refs?

Junior

Answer

Refs are not reactive. Mutating them will not trigger re-renders, so using them to drive UI updates is ineffective.
Quick Summary: Refs hold a mutable container — mutating ref.current doesn't cause a re-render, which is why they're used for DOM access and imperative APIs. Mutating a ref that React uses internally (like a DOM node's style or children) can conflict with React's own DOM management, causing inconsistencies that are difficult to debug.
Q52:

What does useImperativeHandle do?

Junior

Answer

It customizes the instance value exposed to parent components when using refs, often exposing methods like focus().
Quick Summary: useImperativeHandle customizes what is exposed when a parent uses a ref on a child component. Instead of exposing the raw DOM node, you expose specific methods (like focus(), scrollTo()). Used with forwardRef, it gives you controlled, documented imperative API surface on components instead of leaking internal DOM references.
Q53:

What are custom hooks and why are they important?

Junior

Answer

Custom hooks extract reusable logic from components, making code cleaner, modular, and easier to maintain.
Quick Summary: Custom hooks extract reusable stateful logic from components into functions. Instead of duplicating useEffect + useState logic across multiple components, you write it once as useWindowSize or useAuthStatus and use it anywhere. They keep components clean and focused on rendering while the logic stays testable and composable.
Q54:

Why is having too many states in a component problematic?

Junior

Answer

Too many states cause unnecessary re-renders, tightly coupled logic, and reduced component reusability.
Quick Summary: Too many useState calls in one component usually mean the component does too many things. Each state update re-renders the entire component. Hard to reason about which state drives which behavior. Split into smaller components, group related state with useReducer, or move derived values to useMemo instead of storing them as separate state.
Q55:

Why do React 18+ and React 19 emphasize asynchronous rendering?

Junior

Answer

Async rendering prevents UI blocking during heavy updates, improving responsiveness and reducing jank.
Quick Summary: Modern apps need to handle slow networks, large data, and complex UIs without freezing. Synchronous rendering blocks the main thread — if rendering takes 200ms, the browser can't respond to user input. Async rendering (concurrent mode) lets React yield to the browser between chunks of work, keeping the app responsive.
Q56:

How does React’s fiber architecture improve rendering compared to the old stack reconciler?

Mid

Answer

Fiber breaks rendering into small interruptible units, allowing React to pause, resume, or restart work. This prevents UI blocking, enables concurrency, and improves responsiveness during heavy updates.
Quick Summary: The old stack reconciler was recursive and synchronous — once started, it couldn't be interrupted. Fiber is a linked-list-based architecture where each unit of work (fiber) can be paused and resumed. This enables React to split rendering into small chunks, yield to the browser, and prioritize urgent updates (like user input) over non-urgent ones.
Q57:

What causes a component to re-render even if its props haven’t changed?

Mid

Answer

Re-renders occur when its parent re-renders, context value changes, state updates happen, dependencies trigger effects, or Strict Mode double-invokes renders in development.
Quick Summary: A component re-renders when: its own state changes, its parent re-renders (even without prop changes by default), or a Context it consumes changes. React.memo prevents re-renders from parent re-renders when props are shallowly equal. Many perceived "unnecessary" re-renders are actually from Context changes or parent cascades.
Q58:

Why should state updates depending on previous state use a callback function?

Mid

Answer

State updates are asynchronous and batched. Using callbacks like setCount(prev => prev + 1) ensures correct and predictable updates.
Quick Summary: setCount(count + 1) captures count from the closure — if multiple updates are batched, they all use the same stale count and only the last one "wins." setCount(prev => prev + 1) receives the latest state each time. Always use the callback form when the next state depends on the current state.
Q59:

How does React detect whether to reuse a DOM node or replace it?

Mid

Answer

React compares element type and key. If both match, React reuses the existing DOM node; otherwise, it unmounts and creates a new one.
Quick Summary: React checks the element type and key. Same type and key → React reuses the DOM node and updates changed props. Different type → React unmounts the old node and creates a new one from scratch. This is why conditionally rendering different component types at the same position loses state.
Q60:

Why do deeply nested state updates require immutable patterns?

Mid

Answer

React relies on reference comparison. Mutating nested objects keeps the same reference, preventing re-rendering. Spreads or immutable helpers create new references.
Quick Summary: Nested state (objects with nested objects) shares references. If you spread only the top level, nested objects still share the same reference — other parts of state pointing to them see the mutation. Deep cloning everything is expensive. Use Immer (or manual spreading at each level) to create truly independent state copies.
Q61:

What are layout shifts and how can React cause them?

Mid

Answer

Layout shifts occur when UI elements move unexpectedly. React may cause them due to conditional rendering inserts, async content changing structure, or Suspense fallbacks.
Quick Summary: Layout shifts happen when elements change position after initial paint — a classic CLS problem. React can cause this with useEffect that modifies layout (adding elements, changing sizes) after the browser painted. useLayoutEffect runs before paint, preventing visible layout jumps. Also, ensure images have explicit width/height attributes.
Q62:

Why can large Contexts cause performance issues?

Mid

Answer

When context value changes, all consuming components re-render, even those not using the changed fields, causing unnecessary work.
Quick Summary: Context triggers a re-render in every component that consumes it whenever the context value changes — even if the consumer only uses one field of the value. A large Context with many fields that update frequently causes widespread unnecessary re-renders. Split into smaller Contexts or use memoization strategies to limit propagation.
Q63:

How can unnecessary re-renders be prevented when using Context?

Mid

Answer

Split context into smaller contexts, memoize provider values, use useMemo/useCallback, or use selector-based libraries like Zustand or Jotai.
Quick Summary: Prevent Context re-renders by: splitting Context into smaller, focused Contexts (so components only subscribe to what they need), memoizing the Context value object with useMemo (so a new object isn't created every render unless values actually changed), or using Context.Provider around only the components that need it.
Q64:

What is lazy initialization of state in useState?

Mid

Answer

useState(() => ...) runs the initializer only once during the first render, avoiding repeated expensive computations on every render.
Quick Summary: useState(expensiveComputation()) runs expensiveComputation on every render — but only the first render uses the result. Lazy initialization passes a function: useState(() => expensiveComputation()) — React calls it only on the first render. Essential when initial state requires parsing large data or running heavy computation.
Q65:

When does React re-run useMemo?

Mid

Answer

useMemo runs again only when its dependencies change. If dependencies include unstable references, memoization becomes ineffective.
Quick Summary: useMemo re-runs when any value in its dependency array changes (using Object.is comparison). If dependencies are primitive values (strings, numbers), React can accurately detect changes. If dependencies are objects or arrays, a new reference always triggers re-computation — even if contents are the same. Stabilize object dependencies with their own useMemo.
Q66:

Why can memoized components still re-render?

Mid

Answer

Reasons include parent re-renders, non-stable prop references, context changes, or Strict Mode development re-renders.
Quick Summary: React.memo does a shallow comparison of props. If a parent passes a new object or function reference on each render (even with identical content), the memoized child still re-renders. Memoization only works when props are referentially stable — stabilize callbacks with useCallback and objects with useMemo.
Q67:

When should useCallback be preferred over inline functions?

Mid

Answer

Use useCallback when passing functions to memoized children or using them in dependency arrays. Otherwise, it adds unnecessary overhead.
Quick Summary: Use useCallback when a function is passed as a prop to a memoized child (React.memo) — without it, the child gets a new function reference each render and re-renders anyway. Don't use useCallback for every function — the memoization itself has a cost. Only apply it where referential stability actually prevents a re-render you care about.
Q68:

What is the purpose of startTransition?

Mid

Answer

startTransition marks updates as non-urgent so urgent updates like typing render first, keeping UI responsive under heavy workloads.
Quick Summary: startTransition marks state updates as non-urgent transitions. React immediately renders the current UI, then processes the transition update in the background — interruptible by higher-priority updates. If a more urgent update arrives (user typing), React pauses the transition, handles the urgent update, then resumes. Keeps the UI responsive during heavy renders.
Q69:

Why might React skip a render even after a state update?

Mid

Answer

React skips renders when the new state value is strictly equal to the previous state, avoiding unnecessary updates.
Quick Summary: React may bail out of a re-render if the state setter is called with the same value as the current state (Object.is comparison). React detects the value didn't change, skips rendering the component, and doesn't update children. This is automatic — you don't need to manually compare.
Q70:

How does React decide hydration priorities in React 18+?

Mid

Answer

React performs selective hydration, prioritizing interactive components, visible elements, and network-ready content.
Quick Summary: React 18 uses selective hydration: components inside Suspense boundaries are hydrated on demand. If the user interacts with a not-yet-hydrated component, React prioritizes hydrating that boundary immediately, even if other boundaries were registered first. User interaction signals high priority.
Q71:

What is the difference between Streaming SSR and Traditional SSR?

Mid

Answer

Traditional SSR sends HTML only after full rendering. Streaming SSR streams chunks as they are ready, improving first paint and user experience.
Quick Summary: Traditional SSR renders the full HTML on the server, sends it all, then hydrates the entire page before it's interactive. Streaming SSR (React 18) sends HTML chunks as they're ready, starting with the shell, then streaming in Suspense boundary content as their data resolves. Users see content faster and can interact sooner.
Q72:

How do server actions in React 19 differ from traditional API calls?

Mid

Answer

Server actions allow calling server-side functions directly from components without creating API endpoints, reducing boilerplate and enhancing security.
Quick Summary: Server actions in React 19 are async functions that run on the server, called directly from components — no need to create a separate API endpoint, set up fetch calls, or manage CSRF tokens. They're more ergonomic than REST calls and can directly mutate server data, then optionally revalidate the component tree.
Q73:

Why can server components not use browser APIs like window or document?

Mid

Answer

Server components run on the server where browser globals do not exist, making window or document unavailable.
Quick Summary: Server Components run in a Node.js environment on the server — they have no access to the browser's global APIs (window, document, navigator, localStorage). They execute before the page reaches the browser. Any browser-specific code must live in Client Components (marked with "use client") that run after hydration.
Q74:

What is the waterfall problem in SSR and how does Suspense fix it?

Mid

Answer

Waterfall fetching forces sequential loading. Suspense enables parallel data loading and rendering, eliminating delays.
Quick Summary: In traditional SSR, the server must fetch all data, render the full page, and send it — a sequential waterfall. Suspense lets the server stream the HTML shell immediately, then stream in each data-dependent section as its data resolves. Users see the page start loading instead of waiting for all data before seeing anything.
Q75:

Why must keys be stable and unique in React lists?

Mid

Answer

Keys help React correctly match elements during reconciliation. Unstable keys cause incorrect state retention or DOM mismatches.
Quick Summary: Stable keys let React match components between renders — the same key on the same item means React reuses its DOM node and state. Unstable keys (like Math.random()) cause React to destroy and recreate components every render — losing state and causing flicker. Keys must be unique among siblings, not globally.
Q76:

What is tearing in concurrent React?

Mid

Answer

Tearing occurs when parts of the UI read different versions of state during async rendering. React 18 fixes this using consistent rendering and batching.
Quick Summary: Tearing happens in concurrent rendering when React starts rendering with one version of external state, gets interrupted, and resumes with a different version — producing a UI where different parts show different states simultaneously. useSyncExternalStore prevents this by ensuring all reads in a render get the same snapshot of external state.
Q77:

Why do duplicated DOM nodes appear in lists during fast operations?

Mid

Answer

This happens due to unstable or incorrect keys, causing React to reuse DOM nodes incorrectly during rapid updates.
Quick Summary: This typically happens when keys aren't stable — React creates a new component instance instead of updating the existing one, momentarily showing both (old unmounting, new mounting). It can also happen with concurrent rendering where React renders multiple versions of the tree. Stable, unique keys are the primary fix.
Q78:

How does React ensure hooks run in the same order each render?

Mid

Answer

Hooks must be called at the top level and not inside conditions or loops, allowing React to map hook states consistently.
Quick Summary: React internally tracks hook calls by their order in the call stack — hook #1, hook #2, etc. This is why hooks can't be called conditionally or inside loops. If the order changes between renders, React reads the wrong hook's state. React enforces this with a linting rule (rules-of-hooks) and runtime checks in development.
Q79:

Why is returning different numbers of elements across renders problematic?

Mid

Answer

Inconsistent output causes layout shifts, hydration mismatches, and unstable UI trees during re-renders.
Quick Summary: React reconciles by comparing element type at each position. Returning 3 elements sometimes and 1 element other times means React sees different types at different positions and unmounts/remounts. This destroys component state unexpectedly. Use conditional rendering within a stable list structure to keep component identity consistent.
Q80:

What happens when two state updates occur in one event handler?

Mid

Answer

React batches them into a single render for better performance.
Quick Summary: React 18 batches all state updates in one event handler into a single re-render. So setName('Alice'); setAge(30); triggers one render, not two. React collects all updates from the handler, applies them all, then renders once with the final state. This is automatic in React 18 — no unstable_batchedUpdates needed.
Q81:

Why avoid defining styled-components or CSS-in-JS inside components?

Mid

Answer

It recreates component definitions on every render, hurting memoization and performance.
Quick Summary: Styled-components or CSS-in-JS objects defined inside a component are recreated on every render — generating new class names each time. This causes unnecessary style recalculations, can break animations, and adds garbage collection pressure. Define styles outside the component or with stable references at the module level.
Q82:

How does React maintain UI consistency during async rendering?

Mid

Answer

React builds a new UI tree in memory (double buffering) and commits only complete updates, ensuring consistent UI state.
Quick Summary: React uses the transition system and internal lanes to track which renders are in-progress. During concurrent rendering, React maintains consistency by committing all pending updates from one lane atomically before moving to the next. The commit phase is synchronous and non-interruptible — once React starts committing, it finishes.
Q83:

Why is reading DOM values inside render dangerous?

Mid

Answer

Render must stay pure. Reading DOM causes side effects and inconsistent behavior due to multiple render passes.
Quick Summary: Reading DOM properties (offsetHeight, getBoundingClientRect) during render causes layout thrashing — the browser must compute the layout immediately instead of batching it. In concurrent mode, React may run render multiple times, causing multiple forced layouts. Always read DOM in useLayoutEffect or event handlers, not in the render function.
Q84:

What is the purpose of useSyncExternalStore?

Mid

Answer

It ensures consistent subscriptions to external stores like Redux or Zustand during concurrent rendering, preventing tearing.
Quick Summary: useSyncExternalStore safely subscribes React components to external stores (Redux, Zustand, browser APIs). It provides a snapshot function (read current state) and a subscribe function (notify on change). React guarantees all reads use the same snapshot within a render — preventing the tearing problem in concurrent mode.
Q85:

Why memoize only expensive computations and not trivial ones?

Mid

Answer

Memoization has overhead. Overusing it slows performance, so only expensive repeated computations should be memoized.
Quick Summary: useMemo and useCallback have their own overhead: storing the cached value, tracking dependencies, comparing them each render. For trivial computations (adding two numbers, simple string operations), the memoization cost exceeds the computation cost. Only memoize when you've identified a real performance problem through profiling.
Q86:

How does React Fiber schedule work using lanes, and how does it prioritize rendering tasks?

Senior

Answer

React assigns each update to a lane based on priority. High-priority lanes like user input render first, while lower-priority lanes such as background transitions are deferred or interrupted, enabling concurrent rendering.
Quick Summary: React Fiber uses lanes to assign priority to work. Each fiber (unit of work) has a lane (urgent, transition, background). React's scheduler processes the highest-priority lane first. When a high-priority update arrives, React saves the current fiber's progress and starts the high-priority work. After, it resumes or restarts lower-priority work.
Q87:

What is the difference between Scheduler and Reconciler in React’s architecture?

Senior

Answer

Scheduler decides when work should run using priorities and interruption. Reconciler decides what to render by diffing and producing the fiber tree. Both combine to enable concurrency.
Quick Summary: The Scheduler determines when to run work — it uses the browser's message channel to schedule tasks between frames, preventing long tasks that block the main thread. The Reconciler determines what work to do — walking the fiber tree, comparing current and work-in-progress trees, and determining what DOM changes are needed.
Q88:

Why is React’s render phase interruptible but the commit phase is not?

Senior

Answer

Render is pure so it can be paused and resumed safely. Commit mutates the DOM and must run atomically to avoid inconsistent UI.
Quick Summary: The render phase is interruptible because it's pure computation — React calculates what changes are needed but makes no DOM mutations. Interrupting and restarting is safe. The commit phase makes real DOM mutations, fires refs, and runs effects — these are side effects that must complete atomically for the UI to be consistent.
Q89:

How do Suspense boundaries affect the rendering waterfall in SSR?

Senior

Answer

Suspense allows independently fetching components to resolve in parallel. SSR streams chunks as they are ready, removing sequential waterfalls.
Quick Summary: Suspense boundaries divide the SSR HTML into independently flushable sections. React can send the page shell, then stream each boundary as its data arrives — instead of waiting for all data. Each boundary resolves independently, eliminating the cascade where one slow query delays the entire page render.
Q90:

Why is mixing Server Components and Client Components beneficial in large apps?

Senior

Answer

Server Components reduce bundle size and handle data fetching. Client Components manage interactivity. The hybrid model improves performance and developer experience.
Quick Summary: Server Components handle data fetching and heavy rendering — no JS sent to the client for those parts. Client Components handle interactivity — only they download as JavaScript. This split minimizes JS bundle size while keeping data fetching efficient. Static parts render once on the server; interactive parts hydrate on the client.
Q91:

Why are Client Components not allowed to import Server Components?

Senior

Answer

Client bundles run in the browser; server-only code cannot be bundled and would cause unresolved modules and hydration failures.
Quick Summary: Client Components run in the browser — they're part of the JS bundle. Server Components run on the server and are never included in the client bundle. If a Client Component imported a Server Component, that Server Component code would need to be in the client bundle — leaking server-only code and defeating the purpose.
Q92:

What is the biggest challenge when migrating a large SPA to Server Components?

Senior

Answer

The hardest part is deciding boundary placement between server and client components without breaking interactivity, caching, or consistency.
Quick Summary: The biggest challenge is state management that assumed full client-side rendering — global stores, context that wraps everything, and effects for data fetching all need rethinking. Client/Server Component boundaries require careful design. Teams also struggle with understanding what code runs where and why some patterns break.
Q93:

How does React avoid tearing with external stores in concurrent mode?

Senior

Answer

React uses useSyncExternalStore to ensure all components read the same snapshot during render, preventing tearing during concurrent rendering.
Quick Summary: useSyncExternalStore ensures all reads of external state within a single render use the same snapshot. It works by re-rendering synchronously when the external store changes during a concurrent render — React detects the inconsistency and re-does the render synchronously to ensure a tear-free result.
Q94:

When is it better to replace Context with an event-driven state store?

Senior

Answer

Use Redux, Zustand, or Jotai when the app needs fine-grained re-render control, middleware, or cross-app communication. Context causes broad re-renders.
Quick Summary: Context is best for data that rarely changes (auth state, theme, locale). When many components need to react to frequent events (messages arriving, price changes), event-driven stores (Zustand, Redux, EventEmitter) are better — they let components subscribe to specific events and avoid re-rendering all Context consumers on every change.
Q95:

How do you prevent stale closures in hooks?

Senior

Answer

Use functional updates, stable references with useRef, and memoized callbacks via useCallback.
Quick Summary: Stale closures happen when a function captures a variable at one point in time and that variable later changes — but the function still uses the old value. Fix: include all used variables in useEffect dependencies (exhaustive-deps), use refs for values that should always be current without triggering re-renders, or use the functional update form of state setters.
Q96:

Why does React discourage heavy logic inside the render function?

Senior

Answer

Render may run multiple times. Heavy logic causes jank, blocks concurrency, and slows transitions.
Quick Summary: Heavy logic in render runs on every re-render — even if the data hasn't changed. Render should be a pure, cheap function that maps state to UI. Move heavy computations to useMemo (memoize results), useEffect (run after render), or outside the component entirely. Render is called frequently — keep it fast.
Q97:

How do you debug hydration mismatches in server-rendered apps?

Senior

Answer

Check non-deterministic code like random values, time-based content, missing useId, and async data mismatches.
Quick Summary: Hydration mismatches happen when server HTML doesn't match what the client renders. Debug by checking: Date.now() calls (different on server vs client), browser-only APIs accessed during render, non-deterministic data, or conditions based on environment. React 18 shows the specific mismatch in the console to pinpoint the diverging element.
Q98:

Why does React 19 introduce the use hook and how does it affect data fetching?

Senior

Answer

use unwraps promises directly inside components, eliminating useEffect + state boilerplate and improving SSR/RSC data workflows.
Quick Summary: The use hook in React 19 reads a Promise inline in the component body — React suspends if the Promise isn't resolved. Unlike useEffect, use works with Suspense automatically and can be called conditionally. It replaces the awkward useEffect + useState + loading state pattern for data fetching with a much cleaner syntax.
Q99:

When should you use startTransition vs useDeferredValue?

Senior

Answer

startTransition marks state updates as low-priority. useDeferredValue delays updating a derived value. Both prevent blocking urgent UI work.
Quick Summary: startTransition: use when triggering an expensive state update from an event — you control when the transition starts. useDeferredValue: use when receiving a value from outside (like a prop or external store) that you want to defer — you can't control when it updates, but you can delay the expensive re-render that responds to it.
Q100:

What is the purpose of the offscreen component in React?

Senior

Answer

Offscreen allows React to render components in the background and preserve state, enabling instant reveal without cost.
Quick Summary: The offscreen component (still experimental) lets React pre-render components in the background while they're hidden, then show them instantly without a re-render when they become visible. Useful for tab panels, accordions, or route transitions where you want instant reveal without rendering cost at reveal time.
Q101:

Why does React advise splitting components by responsibility rather than file size?

Senior

Answer

Too many responsibilities cause unpredictable re-renders, poor testability, and tight coupling. File size is not the real issue.
Quick Summary: Splitting by responsibility keeps components focused and small. A component doing many things re-renders when any of those things change — unnecessarily. Smaller, focused components only re-render when their specific concern changes. They're easier to memoize, test, and reuse. File size is a consequence of responsibility, not a reason to split.
Q102:

What is the risk of using derived state incorrectly?

Senior

Answer

Duplicated state leads to UI drift and inconsistency. Derived state should be computed on render, not stored.
Quick Summary: Derived state (state that mirrors props) gets out of sync when the parent prop updates but the local state doesn't reset. It creates two sources of truth. Instead, derive values directly from props using useMemo, or use a key prop to fully reset a component when its input changes. Minimize state — derive what you can.
Q103:

What causes React memory leaks in async operations?

Senior

Answer

Async tasks may update unmounted components. Use AbortController, cleanup functions, or transitions.
Quick Summary: Memory leaks happen when async operations (fetch, setInterval, subscriptions) complete after the component unmounts and try to update state — React warns about this. Fix: return a cleanup function from useEffect that cancels the operation (AbortController for fetch, clearInterval, unsubscribe). Always clean up async side effects.
Q104:

What is a hydration boundary and why is it important?

Senior

Answer

Hydration boundaries create isolated hydration zones, enabling selective hydration and reducing blocking time.
Quick Summary: A hydration boundary separates server-rendered content that can be progressively hydrated from the rest of the page. In React 18, Suspense boundaries serve as hydration boundaries — React can hydrate sections independently and prioritize based on user interaction. Without clear boundaries, the entire page must hydrate as one block.
Q105:

Why is tree-shaking more effective in Server Components?

Senior

Answer

RSC code never reaches the client; unused code stays on the server, making tree-shaking automatic.
Quick Summary: Server Components never ship to the client — their code, imports, and dependencies stay on the server. If a Server Component imports a 200KB library for data processing, that library doesn't affect the client bundle. Tree-shaking in bundlers eliminates unused imports; Server Components eliminate entire dependency branches from the client bundle.
Q106:

Why does React encourage referential stability for props to memoized children?

Senior

Answer

Unstable references break shallow comparison and force unnecessary re-renders. useCallback and useMemo ensure stability.
Quick Summary: React.memo does a shallow comparison of props. If a prop is a function or object, React compares references — not content. If the parent creates a new function or object each render, the reference changes, the memo comparison fails, and the child re-renders anyway. Stable references via useCallback and useMemo are what make memo effective.
Q107:

How does React determine when to flush pending updates?

Senior

Answer

React flushes updates based on event boundaries, transitions, microtasks, and scheduler priorities.
Quick Summary: React flushes pending updates when: an event handler completes (automatic batching), startTransition work completes, the Scheduler decides the task queue should flush, or you manually call flushSync. React 18 batches aggressively — it defers flushing to maximize batching, only flushing when it must produce visible output.
Q108:

Why do Suspense boundaries improve user-perceived performance even without SSR?

Senior

Answer

They show fallbacks early, preventing blank screens and minimizing layout shifts during async loading.
Quick Summary: Even without SSR, Suspense improves UX by showing a fallback immediately while a lazy-loaded component loads, preventing the blank flash users see otherwise. It declaratively handles loading states without useState loading flags. With startTransition, Suspense lets React show stale content while new content loads — no blank screens during navigation.
Q109:

What are islands of interactivity and how does React support them?

Senior

Answer

Islands hydrate only interactive parts of the page. React frameworks implement selective hydration for these components.
Quick Summary: Islands of interactivity mean only specific interactive parts of the page hydrate — the rest is static HTML. React supports this via Server Components (never hydrate), Suspense boundaries (hydrate independently), and React.lazy (load Client Components on demand). Frameworks like Astro implement full island architecture using React for the interactive islands.
Q110:

Why does local state for global concerns not scale?

Senior

Answer

Local state becomes duplicated and inconsistent across the app, requiring stores or context for synchronization.
Quick Summary: Local state for global concerns (user auth, theme, cart) lives in one component that must be a parent of all consumers — often creating deeply nested prop drilling or a mega Context. Multiple instances of the same state get out of sync. Global state (Context, Redux, Zustand) keeps one source of truth that all components read from.
Q111:

How does React prevent infinite loops when setters appear in useEffect deps?

Senior

Answer

State setters are stable references, so including them in dependency arrays does not trigger loops.
Quick Summary: React detects when a state setter is in the effect deps but the setter itself is stable (React guarantees setState functions are stable references). It won't re-run just because the setter is listed as a dep — the setter reference never changes. The loop only happens if the effect calls setter with a new value every time it runs.
Q112:

Why must reducers used with useReducer be pure?

Senior

Answer

Impure reducers cause unpredictable state and break React’s deterministic rendering model.
Quick Summary: Pure reducers make state transitions predictable and testable. React may call the reducer multiple times in Strict Mode or concurrent rendering to verify it's pure. An impure reducer (one with side effects or non-deterministic output) would produce different states on each call — causing unpredictable behavior.
Q113:

Why are mutations inside Context values harmful?

Senior

Answer

Mutating context values bypasses reference changes, causing silent inconsistencies and unnecessary re-renders.
Quick Summary: Mutations inside a Context value bypass React's change detection — the Context reference stays the same, so no consumer re-renders. Some see the new data, some see the old data, depending on when they last rendered. Always create new objects for Context values so React detects the change and triggers re-renders in all consumers.
Q114:

What is the biggest bottleneck for large grids or lists?

Senior

Answer

Re-rendering large DOM sections. Solution: virtualization such as react-window or react-virtual.
Quick Summary: Rendering thousands of rows in the DOM causes slow initial render, large memory usage, and slow layout calculations. The DOM simply wasn't designed for that many nodes. Virtualization (react-window, react-virtual) solves this by only rendering rows currently visible in the viewport — a constant number of DOM nodes regardless of list length.
Q115:

Why is hydration expensive for large SPAs?

Senior

Answer

Browser must attach listeners, validate markup, and resolve mismatches on the main thread.
Quick Summary: Hydration must attach event handlers to every interactive DOM node and run all components' initialization logic client-side — for a large SPA, this means executing a large JS bundle and running React reconciliation over the entire component tree. Progressive/selective hydration (React 18) helps by hydrating in priority order rather than all at once.
Q116:

How does React guarantee atomic state updates in concurrent mode?

Senior

Answer

React maintains current and work-in-progress trees. Commit replaces a whole subtree at once, ensuring atomicity.
Quick Summary: React uses lanes to batch related updates. When multiple state updates occur (within a transition, for example), React groups them into the same lane and commits them all together atomically. The commit phase is synchronous — no interruptions allowed. This guarantees users always see a consistent UI, never a half-applied state.
Q117:

Why can overusing React.memo degrade performance?

Senior

Answer

Memo adds comparison overhead. Often re-rendering is cheaper than shallow comparisons.
Quick Summary: React.memo adds comparison overhead on every parent render — it compares all props with Object.is. For cheap components that rarely have prop changes, this comparison costs more than just re-rendering. It also requires stabilizing all props with useCallback/useMemo, adding maintenance burden. Profile first; memoize only confirmed bottlenecks.
Q118:

How do you prevent race conditions in concurrent data fetching?

Senior

Answer

Use request versioning, AbortController, transitions, or server components to prevent out-of-order updates.
Quick Summary: Race conditions happen when two concurrent fetches (triggered by fast input changes) resolve in the wrong order. Fix with: AbortController to cancel the previous fetch when a new one starts, a cleanup flag in useEffect that discards results if the component re-rendered with new props, or a data-fetching library that handles this automatically.
Q119:

Why does React 19 recommend using actions instead of client API calls?

Senior

Answer

Actions execute server code directly, simplifying mutations, validation, error handling, and revalidation.
Quick Summary: React 19 Server Actions let you define server-side functions called directly from components. They handle optimistic updates, loading states, and error handling via useOptimistic and useFormStatus. The framework wraps network calls, serialization, and CSRF protection automatically — less boilerplate than manual fetch to a REST endpoint.
Q120:

How does React avoid inconsistent UI when multiple updates are queued?

Senior

Answer

React processes updates in an ordered queue using lane priorities to maintain determinism.
Quick Summary: React processes all queued updates in the same batch atomically before committing to the DOM. It uses the work-in-progress tree to compute the full result of all updates, then commits the final tree in one synchronous pass. Users never see intermediate states — the DOM goes from one consistent state to the next.
Q121:

Why are heavy animations better with requestAnimationFrame than React state?

Senior

Answer

React state does not synchronize with 60fps rendering. rAF ensures frame-perfect updates.
Quick Summary: React state updates are batched and processed asynchronously — not frame-synchronized. Animations updated via React state can miss frames and feel janky. requestAnimationFrame runs exactly once per frame, before the browser paints, synchronized with the display refresh rate. For smooth animations, update the DOM directly via requestAnimationFrame or use CSS transitions/animations.
Q122:

What causes zombie child components in concurrent React?

Senior

Answer

Outdated render passes create zombie children. React discards stale work to avoid committing them.
Quick Summary: Zombie children are child components that are still mounted after their parent's data no longer considers them valid — they have stale props and keep responding to state updates for data that may have been deleted. Happens when parent re-renders are delayed in concurrent mode. Proper key management and guarding against stale data in effects prevents this.
Q123:

When does React abort an entire render?

Senior

Answer

React aborts when higher-priority updates arrive or required data changes mid-render.
Quick Summary: React aborts an entire render when: an unhandled error is thrown during rendering (triggers the nearest error boundary), a higher-priority update preempts the current render (concurrent mode restarts with the new priority), or the component tree structure changes such that in-progress work is no longer valid.
Q124:

How does React enable background data loading without blocking UI?

Senior

Answer

Using Suspense, Streaming SSR, Offscreen rendering, and Server Components to load data in parallel.
Quick Summary: Suspense enables background data loading: React renders the current visible content while a data fetch runs in the background. When the data resolves, React seamlessly swaps in the new content without blocking the UI. With startTransition, the current UI stays visible and interactive during the background load — no loading spinner required.
Q125:

Why is Render-as-You-Fetch superior to Fetch-Then-Render?

Senior

Answer

It begins rendering while data loads, eliminating idle time and improving performance with Suspense and RSC.
Quick Summary: Fetch-Then-Render: load all data, then render — page is blank until data arrives. Render-as-You-Fetch: start rendering immediately and stream data in as it arrives using Suspense. Users see content progressively instead of a blank screen. Critical data unblocks the shell; secondary data streams in later. Net effect: faster perceived load time.
Q126:

How does React Fiber implement cooperative scheduling using the call stack without blocking the main thread?

Expert

Answer

Fiber creates a linked list tree where each unit of work is a fiber node. Instead of recursively calling functions, React manually iterates the tree, yielding control back to the browser using shouldYield so higher-priority events can run, enabling cooperative multitasking.
Quick Summary: Fiber implements cooperative scheduling using a linked-list work loop instead of the call stack. Each fiber is one unit of work. React's scheduler checks if there's a higher-priority task or a frame deadline after completing each fiber. If yes, it yields control to the browser, then resumes from where it left off. No call stack explosion, no blocking.
Q127:

Why does React split rendering into begin work and complete work phases inside the reconciler?

Expert

Answer

beginWork calculates changes and creates or updates child fibers, while completeWork builds DOM nodes or side-effect lists. This separation allows React to pause between units of work for better concurrency.
Quick Summary: Begin work processes a fiber top-down — determining what children it renders, creating child fibers, reconciling with previous renders. Complete work processes a fiber bottom-up — collecting effects, building the updated props, and assembling the result. This two-pass structure lets React walk the tree once without recursion.
Q128:

How does React handle priority inversion when low-priority tasks block high-priority UI updates?

Expert

Answer

React uses lanes and entanglement mapping so high-priority lanes interrupt low-priority work. React reuses partial work and discards stale renders to maintain responsiveness.
Quick Summary: React's scheduler uses exponential backoff for low-priority tasks that get preempted repeatedly. If a low-priority task keeps getting interrupted, its priority gradually increases to prevent starvation. High-priority tasks (user input, Discrete events) get their own lane and always preempt lower lanes.
Q129:

How does React store and compare alternate trees to guarantee atomic commits?

Expert

Answer

Each component has a current fiber and a work-in-progress fiber. During commit, React swaps pointers atomically to avoid partial UI updates.
Quick Summary: React maintains a "current" fiber tree (displayed UI) and a "work-in-progress" tree (being computed). All changes happen on the work-in-progress tree. Only when the entire tree is computed and reconciled does React atomically swap the two — flipping a single pointer. The current tree becomes the previous tree for the next render.
Q130:

How does React’s diffing algorithm optimize keyed vs non-keyed lists internally?

Expert

Answer

Keyed diffing builds a keyed map to detect moves, deletions, and insertions. Non-keyed diffing assumes positional alignment, which is faster but incorrect for reordering.
Quick Summary: For keyed lists, React builds a map of key → fiber, then matches new elements to existing fibers by key — O(n) instead of O(n²) comparison. For non-keyed lists, React compares by position. Keys allow React to detect moves, insertions, and deletions precisely, reusing DOM nodes for moved items instead of destroying and recreating them.
Q131:

How does React optimize Suspense boundaries through early reveal and delayed placeholder strategies?

Expert

Answer

React reveals resolved subtrees early and delays fallback rendering to avoid flicker using revealTimers and cache heuristics.
Quick Summary: React uses two strategies: if data resolves quickly (under ~250ms), React delays showing the fallback at all — the content appears directly. If data is slow, React shows the fallback immediately. This prevents unnecessary fallback flashes for fast connections while still providing feedback for slow ones.
Q132:

Why are Promise boundaries essential in the React 19 use hook implementation?

Expert

Answer

The use hook integrates directly into the fiber loop. When a promise is encountered, React suspends the fiber, stores continuation, and retries when resolved—similar to coroutines.
Quick Summary: The use hook throws a Promise when data isn't ready — React catches it via a try/catch around the component render. React stores the Promise internally, subscribes to its resolution, and when the Promise resolves, React schedules a re-render of that Suspense boundary. Promise boundaries make throwing-as-control-flow predictable.
Q133:

How does React ensure that streamed SSR content from the server matches hydration order on the client?

Expert

Answer

React tags streamed chunks with react-id markers and uses a hydration priority queue to hydrate components in the correct order.
Quick Summary: React streaming SSR sends HTML chunks with embedded script tags containing data for each Suspense boundary. On the client, React processes these chunks in order, using a list-based hydration queue. If chunks arrive out of order (HTTP/2 push), React buffers and applies them in the correct sequence using their boundary IDs.
Q134:

Why is Suspense fundamentally incompatible with synchronous rendering models?

Expert

Answer

Suspense requires pausing and resuming rendering. Synchronous models cannot interrupt execution, making Suspense impossible without async fiber architecture.
Quick Summary: Suspense requires the rendering model to be interruptible — a component can stop mid-render (by throwing a Promise) and resume later. Synchronous rendering models run to completion; they have no mechanism to suspend mid-tree and resume later. Concurrent mode's interruptible fiber architecture is a prerequisite for Suspense to work.
Q135:

How does React avoid memory explosion when many suspended components are waiting for promises?

Expert

Answer

React uses ref-counted wakeable objects and deduplicates promise listeners to prevent memory overhead.
Quick Summary: React deduplicates suspended Promises — if multiple components suspend on the same Promise, React only resolves it once. Resolved Promise results are cached in the fiber tree during the current render, then discarded when the render commits. React doesn't hold large Promise result buffers — it resolves, commits, and moves on.
Q136:

Explain how React reconciler uses bailing out to skip unnecessary subtrees during rendering.

Expert

Answer

React skips reconciliation when props, state, and context are unchanged via shallow comparison, reusing the previous fiber subtree.
Quick Summary: Bailing out means React skips rendering a subtree entirely when it can prove the output won't change. This happens when React.memo comparison passes, when useState returns the same value, or when a Context consumer's consumed value hasn't changed. React short-circuits the fiber work loop for that subtree — no reconciliation, no diffing, no DOM work.
Q137:

How does React optimize large forms where controlled inputs cause heavy re-renders?

Expert

Answer

React uses batched updates, event priority, offscreen rendering, browser input buffering, or hybrid refs for better performance.
Quick Summary: For large forms, avoid controlled inputs for fields that don't need real-time validation — use uncontrolled inputs (via refs) or form libraries like React Hook Form that minimize re-renders. Split the form into smaller components so only the changed field's component re-renders. Debounce expensive derived state computations.
Q138:

Why is the React Server Components architecture inherently more cacheable than client-rendered components?

Expert

Answer

RSC output is serializable and dependency-tracked, enabling fine-grained caching at the module or function level.
Quick Summary: Server Components produce a static output determined by their props and server-side data — same inputs always produce the same output. This output can be cached at the edge (CDN) or in memory. Client Components depend on browser state (user input, events) — inherently dynamic, not cacheable. Moving logic to Server Components improves cacheability.
Q139:

How does React prevent stale hydration attachments when HTML streaming arrives out of order?

Expert

Answer

React buffers out-of-order chunks and only hydrates them when boundary segments are complete.
Quick Summary: React assigns each Suspense boundary a unique ID in the HTML stream. When streaming HTML chunks arrive, React's client-side code matches each chunk to its boundary ID. If chunks arrive out of order, React buffers them. DOM insertion happens in the correct boundary order regardless of network delivery order.
Q140:

What is the progressive selective hydration algorithm introduced in React 18?

Expert

Answer

React hydrates based on interaction priority, visibility, and lane scheduling to reduce blocking time.
Quick Summary: Progressive selective hydration prioritizes hydrating Suspense boundaries that the user interacts with first. If a user clicks on a not-yet-hydrated area, React interrupts other in-progress hydration work, hydrates that specific boundary immediately (making it interactive), then resumes hydrating the rest in background.
Q141:

Why can React’s lane model guarantee deterministic rendering even under concurrency?

Expert

Answer

Lane priorities, expiration times, and entanglement rules ensure predictable update ordering.
Quick Summary: React's lane model assigns each update to a specific bit in a lane bitmask (32-bit integer). Each lane represents a priority level. React processes lanes in priority order. Because lanes are bitmask operations (fast) and priorities are fixed, React can deterministically schedule and merge concurrent updates — the result is always the same for the same inputs.
Q142:

Why can mixing Context Providers deeply inside rendering loops cause reconciler thrashing?

Expert

Answer

Each Provider update invalidates all consumers; inside loops, this causes exponential rerenders.
Quick Summary: Creating Context Providers inside rendering loops means each render creates new Context values and potentially new Provider component instances. This busts the Context value comparison, causing all consumers to re-render. Providers that recreate their value on every render of a parent cause "Context thrashing" — constant reconciler work for no real change.
Q143:

How does React 19 handle action revalidation to avoid inconsistent states across the app?

Expert

Answer

React invalidates cached RSC trees referencing stale data and regenerates affected segments using dependency graph invalidation.
Quick Summary: React 19 server actions trigger revalidation after mutation — by default, the current route's data is re-fetched and the component tree is re-rendered with fresh data. You can control revalidation scope with revalidatePath or revalidateTag. This ensures state is consistent post-action without manual cache invalidation.
Q144:

Explain the internals of useSyncExternalStore and how it guarantees tear-free reads.

Expert

Answer

React ensures atomic snapshot reads and compares server/client snapshots, preventing tearing during concurrent renders.
Quick Summary: useSyncExternalStore takes a subscribe function and a getSnapshot function. On render, React calls getSnapshot and renders with that value. It also registers a listener via subscribe. If the store changes during a concurrent render, React compares the new snapshot — if different from the render-time snapshot, it re-renders synchronously to prevent tearing.
Q145:

How does React dedupe heavy selectors inside Context and Redux with concurrent rendering?

Expert

Answer

React caches derived values via memoized selectors and fine-grained subscriptions.
Quick Summary: useSyncExternalStore and libraries like Jotai/Zustand expose stable selectors — only components using a specific slice subscribe to changes in that slice. With concurrent rendering, Redux and Context use subscription models that check current vs previous values before re-rendering. Memoized selectors that return stable references prevent cascade re-renders.
Q146:

What happens when a Server Component imports a Client Component that imports another Server Component?

Expert

Answer

React fails the build. Server Components cannot appear under Client boundaries.
Quick Summary: A Server Component that imports a Client Component is fine — the Client Component is marked for client-side rendering. But a Client Component can't import a Server Component directly because the Client Component is in the client bundle and Server Components must never be. However, a Server Component can pass a Server Component as a JSX prop (children) to a Client Component.
Q147:

How does React resolve cyclic dependency chains in async Suspense trees?

Expert

Answer

React tracks pending wakeables and detects repeated suspension cycles, surfacing errors to boundaries.
Quick Summary: React tracks already-resolved Suspense trees in the fiber structure. When a suspended Promise in an async tree depends on another suspended Promise, React resolves them in dependency order. React deduplicates identical Promises (same reference) and resolves the dependency chain bottom-up, retrying parent boundaries when child dependencies resolve.
Q148:

How does the fiber system reuse DOM nodes while swapping fiber trees?

Expert

Answer

DOM nodes attach to the hostFiber. During commit, React updates props/events without destroying nodes.
Quick Summary: During commit, React walks the work-in-progress fiber tree and matches each fiber to an existing DOM node. If the fiber's type and key match the current DOM node, React updates it in-place (reuses the node). If they don't match, React removes the old node and inserts the new one. DOM node reuse minimizes browser layout recalculation.
Q149:

What is the transition tree and how does React use it during low-priority renders?

Expert

Answer

React marks updates inside startTransition as belonging to a separate transition tree that can pause, resume, or discard work.
Quick Summary: The transition tree is the work-in-progress tree being built for a low-priority transition update. React renders it concurrently alongside the current tree. If an urgent update arrives, React abandons the transition tree, handles the urgent update on the current tree, and then starts a new transition tree incorporating all pending updates.
Q150:

How does React implement high-priority interruptions during slow list diffing operations?

Expert

Answer

React checks scheduler signals; shouldYield() pauses reconciliation to let high-priority tasks run.
Quick Summary: React's scheduler uses postMessage to break work into tasks. Each task processes fibers until the frame budget (~5ms) is exhausted, then yields. A high-priority interrupt (user input) is registered in the scheduler queue with a higher priority. On the next scheduler cycle, it runs the high-priority task first before resuming list diffing.
Q151:

What are hydration bubbles and how does React use them to allow partial interactive UI?

Expert

Answer

Hydration bubbles hydrate children first, then expand upward, enabling selective interactivity.
Quick Summary: Hydration bubbles are the units of progressive hydration — each Suspense boundary is a bubble that hydrates independently. React attaches event listeners to the document root before hydration completes (delegation). When a user interacts with an unhydrated bubble, React synchronously hydrates just that bubble and replays the event.
Q152:

How does React’s event system maintain compatibility with concurrent rendering?

Expert

Answer

React replays events fired before hydration finishes, ensuring consistent event processing.
Quick Summary: React uses a root-level event listener (attached to the container div) for all synthetic events. In concurrent mode, events are processed after the current render commits, not during. React stores the event, commits the render, then dispatches it. This guarantees event handlers always see a fully consistent, committed DOM state.
Q153:

Why does React avoid triggering layout thrashing even with layout effects?

Expert

Answer

React batches DOM reads/writes into phases to avoid bouncing layout calculations.
Quick Summary: useLayoutEffect runs synchronously after DOM mutations but before the browser paints. React batches all useLayoutEffect callbacks and runs them together after the commit. Because this happens in the same synchronous execution context as the DOM write, the browser doesn't get a chance to paint between the write and the layout measurement — no thrash.
Q154:

How does React determine when an effect cleanup should run during concurrent re-renders?

Expert

Answer

React only cleans up effects from committed renders; work-in-progress renders are discarded without cleanup.
Quick Summary: Effect cleanup timing in concurrent mode: React runs cleanup when a component unmounts, or before re-running an effect. In concurrent mode, React may start rendering a component, then abort and discard it before committing — effects don't run for aborted renders. Cleanup runs only for effects that were actually committed to the DOM.
Q155:

How does the React compiler React Forget optimize component re-renders automatically?

Expert

Answer

React Forget auto-generates memoization logic, stabilizing references and eliminating the need for manual useMemo/useCallback.
Quick Summary: React Forget (the React compiler) statically analyzes component code and automatically inserts useMemo and useCallback where values are stable across renders. Instead of manually memoizing, the compiler identifies which values can be reused and generates the memoization code for you. Goal: performance of memoized code without the manual effort.

Curated Sets for React

No curated sets yet. Group questions into collections from the admin panel to feature them here.

Ready to level up? Start Practice