AceDevHub

Interview questions

100 React Interview Questions and Answers (2026)

100 React interview questions and answers for 2026 covering components, JSX, props, state, Hooks, rendering, forms, effects, performance, architecture, code output, and real-world scenarios from beginner to advanced.

100 questionsBeginnerIntermediateAdvancedCode OutputScenario
1

Beginner React Interview Questions

Question 1BeginnerConcept

What is React, and why is it used?

Direct answer

React is a JavaScript library for building component-based user interfaces that update declaratively when application data changes.

React lets developers describe a UI as a tree of components and update that UI by changing props or state instead of manually issuing DOM commands.

  • Component model: split the interface into reusable, composable pieces.
  • Declarative rendering: describe what the UI should look like for the current data.
  • Cross-platform model: React itself defines the component model; renderers such as React DOM target specific environments.
Question 2BeginnerComparison

Is React a library or a framework?

Direct answer

React is a library focused on building user interfaces, while a framework usually defines a broader application structure and includes more built-in solutions.

AreaReactTypical full-stack framework
Primary scopeUI components and renderingApplication structure across multiple concerns
RoutingNot built into core ReactUsually integrated or prescribed
Data/loading conventionsCan be added in many waysOften provides conventions or APIs
Project structureFlexibleUsually more opinionated

React can be used by itself, but production applications often use it through a React framework that adds routing, server rendering, data loading, and build conventions.

Question 3BeginnerConcept

What is a React component?

Direct answer

A React component is a reusable unit of UI, typically written as a JavaScript function that returns JSX.

A component receives inputs such as props and can use React features such as state and context to calculate the JSX it returns.

UserCard.jsx
function UserCard({ name }) {
  return (
    <article>
      <h2>{name}</h2>
    </article>
  );
}
Question 4BeginnerComparison

What is the difference between function components and class components in React?

Direct answer

Function components are ordinary functions that return JSX and use Hooks for React features; class components use React.Component and lifecycle methods and are mainly encountered in older code.

FeatureFunction componentClass component
DefinitionJavaScript functionClass extending React.Component
State and React featuresHooks such as useState and useEffectthis.state and lifecycle methods
this bindingNot requiredOften relevant
New React codeStandard approachSupported, but mostly legacy/maintenance

Modern React documentation teaches function components first. Hooks are designed for function components and cannot be called inside class components.

Question 5BeginnerConcept

What is JSX in React?

Direct answer

JSX is a JavaScript syntax extension that lets you write HTML-like markup inside JavaScript and is transformed into the element descriptions React renders.

JSX is not HTML and it is not a separate templating language. It lets rendering logic and markup stay together inside a component.

Greeting.jsx
const user = "Aisha";

export default function Greeting() {
  return <h1>Hello, {user}</h1>;
}
Question 6BeginnerComparison

How is JSX different from HTML?

Direct answer

JSX looks like HTML but follows JavaScript-oriented rules such as camel-cased properties, JavaScript expressions in braces, and stricter element nesting.

ConcernHTMLJSX
CSS classclassclassName
Label associationforhtmlFor
JavaScript valuesNot embedded with JSX syntaxUse {expression}
Attribute namingOften lowercaseMany DOM properties use camelCase
Empty elementsHTML rules varyMust be closed, e.g. <img />

A component must return a single JSX tree. When you do not want an extra DOM wrapper, you can group siblings with a React Fragment.

Question 7BeginnerConcept

What are props in React?

Direct answer

Props are read-only inputs passed from a parent to a component to configure what that component renders or how it behaves.

Props can contain strings, numbers, objects, arrays, functions, or JSX. A component receives a snapshot of its props for each render.

Profile.jsx
function Avatar({ name, size = 48 }) {
  return <img alt={name} width={size} height={size} />;
}

export default function Profile() {
  return <Avatar name="Ada" size={64} />;
}
Question 8BeginnerComparison

What is the difference between props and state in React?

Direct answer

Props are inputs supplied by a parent, while state is component memory managed by React and updated by the component through state setters.

FeaturePropsState
SourceUsually parent componentComponent using a state Hook
Mutated directly?NoNo; use the state setter
PurposeConfigure a componentRemember changing information
Can trigger a render?New props arrive during parent-driven renderingA state update can schedule a render

Both props and state should be treated as immutable snapshots for a particular render.

Question 9BeginnerConcept

What is the children prop in React?

Direct answer

The children prop contains the JSX nested inside a component's opening and closing tags, enabling flexible component composition.

Card.jsx
function Card({ children }) {
  return <section className="card">{children}</section>;
}

export default function Page() {
  return (
    <Card>
      <h2>Account</h2>
      <button>Save</button>
    </Card>
  );
}

The Card component does not need to know which exact child elements it wraps. This makes wrapper and layout components highly reusable.

Question 10BeginnerConcept

What is state in React?

Direct answer

State is component-specific memory that React preserves between renders and uses to produce updated UI.

Use state when a component needs to remember information that can change over time, such as an input value, selected tab, or whether a modal is open.

  • Persistent across renders: local variables reset when the function runs again, state does not.
  • Private to a component instance: rendering the same component twice creates independent state for each position.
  • Updated through React: use a setter instead of mutating the state value directly.
Question 11BeginnerConcept

How does the useState Hook work?

Direct answer

useState declares a state variable and returns the current state value together with a setter that schedules an updated render.

Counter.jsx
import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}
count
The state value for the current render
setCount
The setter used to request the next state
0
The initial state used on the first render
Question 12BeginnerCode Output

Why does React state behave like a snapshot, and what does this handler log?

Direct answer

If count is 0 when the click starts, the handler logs 0; setCount schedules a future render where count becomes 1.

Counter.jsx
function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
    console.log(count);
  }

  return <button onClick={handleClick}>{count}</button>;
}
Output
0

Each render receives its own state snapshot. Calling the setter queues an update, but it does not rewrite the count variable inside the event handler that is already running.

Question 13BeginnerConcept

What causes a React component to re-render?

Direct answer

A component can render initially and then render again when its state updates, when its parent renders it again, or when a context value it reads changes.

  • Local state update: a setter such as setCount can schedule a render.
  • Parent rendering: by default, rendered child components are evaluated again with the parent's current props.
  • Context update: components reading that context receive the new value and render again.

A React render does not automatically mean the DOM changes. React can render a component, compare the result, and commit no DOM update if nothing visible changed.

Question 14BeginnerComparison

What are the render and commit phases in React?

Direct answer

During render React calculates what the component tree should look like; during commit React applies the required changes to the DOM and attaches refs.

PhaseWhat React doesSide effects?
RenderCalls components and calculates the next UIRendering logic should stay pure
CommitApplies required DOM changes and updates refsDOM is being synchronized
Browser paintBrowser displays the resulting pixelsHandled by the browser

A render can happen without producing a DOM mutation. This distinction is essential when debugging repeated renders or performance.

Question 15BeginnerPractical

How do you handle events in React?

Direct answer

Define an event-handler function and pass that function to a JSX event prop such as onClick, rather than calling it during render.

SaveButton.jsx
export default function SaveButton() {
  function handleClick() {
    console.log("Saved");
  }

  return <button onClick={handleClick}>Save</button>;
}

React event props use names such as onClick and onChange. Event handlers are the right place for side effects caused by a specific user action.

Question 16BeginnerPractical

How does conditional rendering work in React?

Direct answer

React uses normal JavaScript control flow such as if statements, ternaries, logical &&, and returning null to decide which JSX should be rendered.

Status.jsx
function Status({ isLoggedIn }) {
  if (!isLoggedIn) {
    return <LoginButton />;
  }

  return <Dashboard />;
}
  • if / early return: useful when whole branches differ.
  • condition ? A : B: useful for choosing between two JSX expressions.
  • condition && A: useful when an element is optional.
  • return null: render nothing from that component.
Question 17BeginnerPractical

How do you render a list in React?

Direct answer

Use JavaScript array operations such as map() to create JSX for each item and give each rendered sibling a stable key.

UserList.jsx
const users = [
  { id: "u1", name: "Mina" },
  { id: "u2", name: "Ravi" },
];

export default function UserList() {
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

React does not introduce a special loop syntax for JSX. You usually transform arrays with normal JavaScript methods such as map() and filter().

Question 18BeginnerConcept

What are keys in React, and why are they important?

Direct answer

Keys are stable identifiers for sibling elements in a rendered collection that help React match each item with the same item across inserts, removals, and reordering.

A good key comes from the data itself, such as a database ID. Keys must be unique among siblings and should remain stable between renders.

TodoList.jsx
{todos.map((todo) => (
  <TodoItem key={todo.id} todo={todo} />
))}
Question 19BeginnerScenario

When is using an array index as a React key a problem?

Direct answer

An array index is a poor key when items can be inserted, deleted, filtered, or reordered because the same index can become associated with different data.

List behaviorIndex key risk
Static list that never changes orderOften low
Insert or delete itemsComponent identity can shift
Sort or reorder itemsState may follow the position instead of the item
Editable rowsUser input can appear attached to the wrong row

Prefer a stable ID from the data. Generating keys with Math.random() during render is even worse because every render creates new identities.

Question 20BeginnerConcept

What is a React Fragment?

Direct answer

A React Fragment groups multiple JSX children without adding an extra wrapper element to the DOM.

Name.jsx
import { Fragment } from "react";

export default function Name() {
  return (
    <>
      <dt>First name</dt>
      <dd>Ada</dd>
    </>
  );
}

The short syntax <>...</> is convenient when no Fragment key is needed. Use the explicit <Fragment key={...}> form when rendering keyed fragments in a list.

Question 21BeginnerComparison

What is the difference between controlled and uncontrolled components in React?

Direct answer

A controlled value is driven by React props or state, while an uncontrolled value keeps important state internally, often in the DOM for native form inputs.

FeatureControlledUncontrolled
Current valueSupplied by React state/propsManaged internally or by the DOM
Typical text inputvalue + onChangedefaultValue or no value prop
CoordinationEasy for parent logic to controlLess configuration
Source of truthReact state/parentElement or component's local state

The terms also apply more broadly to component design: a component is more controlled when important behavior is driven by props from its parent.

Question 22BeginnerPractical

How do you create a controlled input in React?

Direct answer

Store the input value in state, pass that state to value, and synchronously update it from the input's onChange handler.

SearchBox.jsx
import { useState } from "react";

export default function SearchBox() {
  const [query, setQuery] = useState("");

  return (
    <input
      value={query}
      onChange={(event) => setQuery(event.target.value)}
      placeholder="Search"
    />
  );
}

For a controlled text input, React state is the source of truth. Checkboxes and radio buttons are controlled with checked rather than their text value.

Question 23BeginnerConcept

What does lifting state up mean in React?

Direct answer

Lifting state up means moving shared state to the closest common parent so multiple child components can read and update one source of truth.

When sibling components must stay synchronized, storing separate copies of the same state creates duplication. Move the state to their common parent and pass values and handlers down as props.

Accordion.jsx
function Accordion() {
  const [activeId, setActiveId] = useState(null);

  return (
    <>
      <Panel id="a" activeId={activeId} onSelect={setActiveId} />
      <Panel id="b" activeId={activeId} onSelect={setActiveId} />
    </>
  );
}
Question 24BeginnerConcept

What does one-way data flow mean in React?

Direct answer

One-way data flow means data is normally passed down the component tree through props, while children request changes by invoking callbacks or updating shared state through an owning abstraction.

  • Parent owns data: the parent decides the current value.
  • Data flows down: children receive current values through props or context.
  • Events communicate intent: children can call handlers supplied by the owner to request an update.

This model makes it easier to identify the single source of truth for each piece of application state.

Question 25BeginnerConcept

What are Hooks in React?

Direct answer

Hooks are React functions that let function components use features such as state, context, refs, effects, and reusable stateful logic.

  • useState: component state.
  • useEffect: synchronization with external systems.
  • useRef: mutable values or DOM references that do not trigger rendering.
  • useContext: reads and subscribes to a context value.

Custom Hooks let you combine built-in Hooks into reusable logic. Their names conventionally begin with use.

Question 26BeginnerConcept

What are the Rules of Hooks?

Direct answer

Most Hooks must be called at the top level of a function component or custom Hook so React sees them in a consistent order on every render.

  • Top level: do not call ordinary Hooks inside loops, conditions, nested callbacks, or after conditional returns.
  • React functions: call Hooks from function components or custom Hooks, not ordinary JavaScript functions or class components.
  • Static order: React relies on stable Hook call ordering to associate state with each call.

The React use() API has special calling rules and is an exception to some ordinary Hook restrictions, so avoid overgeneralizing the rule to every function beginning with use.

Question 27BeginnerConcept

What is useEffect in React?

Direct answer

useEffect is a Hook for synchronizing a component with an external system after React commits an update.

Typical external systems include network connections, browser APIs, subscriptions, timers, analytics integrations, or third-party widgets.

chat-effect.js
useEffect(() => {
  const connection = createConnection(roomId);
  connection.connect();

  return () => connection.disconnect();
}, [roomId]);
Question 28BeginnerConcept

What do the dependency array and cleanup function do in useEffect?

Direct answer

The dependency array controls when an Effect must resynchronize, and the optional cleanup function undoes the previous synchronization before the Effect runs again or the component is removed.

FormTypical behavior
useEffect(setup)Runs after every committed render
useEffect(setup, [])No reactive dependencies; setup is associated with mounting semantics
useEffect(setup, [a, b])Re-synchronizes when a or b changes by React's dependency comparison
return cleanupRuns before re-synchronizing and when the component is removed

Dependencies should include the reactive values used by the Effect. In development Strict Mode, React can run an extra setup-and-cleanup cycle to expose missing cleanup logic.

Question 29BeginnerConcept

What is useRef in React?

Direct answer

useRef stores a mutable value that persists between renders without causing a re-render when its current property changes.

Search.jsx
import { useRef } from "react";

function Search() {
  const inputRef = useRef(null);

  function focusSearch() {
    inputRef.current?.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={focusSearch}>Focus</button>
    </>
  );
}
  • DOM access: focus, scroll, or measure an element.
  • Mutable non-visual value: store timer IDs or other values that should survive renders without changing JSX.
Question 30BeginnerComparison

What is the difference between useRef and useState?

Direct answer

useState stores render-driving data and schedules renders when updated; useRef stores mutable persistent data whose changes do not schedule a render.

FeatureuseStateuseRef
Persists between rendersYesYes
Update triggers renderYes, when React accepts a changed stateNo
Read in renderNormal useAvoid mutable ref reads for render-driving logic
Common useVisible component dataDOM handles, timer IDs, mutable non-visual values

Both preserve information across renders, but only state participates directly in React's declarative rendering model.

Question 31BeginnerConcept

What are Context and useContext in React?

Direct answer

Context lets a parent provide a value to descendants without manually passing that value through every intermediate component, and useContext reads and subscribes to it.

Theme.jsx
import { createContext, useContext } from "react";

const ThemeContext = createContext("light");

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>Save</button>;
}

Context is useful for values that are needed by many components at different depths, such as theme, locale, or authenticated-user information.

Question 32BeginnerConcept

What is the Virtual DOM in React, and how does reconciliation work?

Direct answer

The Virtual DOM is a common name for React's in-memory representation of UI; reconciliation is the process React uses to match a newly rendered tree with the previous one and determine what should be preserved or changed.

When props, state, or context changes, React renders the next element tree. React then matches that result with the previous tree and commits the required changes to the host environment such as the browser DOM.

  • Element/component type: helps React decide whether an existing subtree represents the same kind of UI.
  • Keys: help React preserve identity among siblings when collections change.
  • Stable position and identity: influence whether component state is preserved or reset.
2

Intermediate React Interview Questions

Question 33IntermediateConcept

How does React batch state updates, and why does it matter?

Direct answer

React queues state updates during an event and processes them together before the next render, reducing unnecessary intermediate renders and keeping each render internally consistent.

Calling a state setter does not immediately mutate the state variable from the current render. React queues the update and normally processes the queued work after the event handler has finished.

  • Performance: several related updates can be handled in one render instead of producing a partially updated UI after every setter call.
  • Snapshot behavior: code still sees the state values captured by the render that created the current event handler.
  • Intentional events: separate user interactions such as separate clicks are handled independently rather than being merged into one logical event.
Question 34IntermediatePractical

When should you use the functional form of a React state setter?

Direct answer

Use a functional updater when the next state depends on the previous state, especially when multiple updates may be queued before React renders again.

Counter.jsx
function Counter() {
  const [count, setCount] = useState(0);

  function addThree() {
    setCount(c => c + 1);
    setCount(c => c + 1);
    setCount(c => c + 1);
  }

  return <button onClick={addThree}>{count}</button>;
}

Each updater receives the result of the previous queued update. This makes setCount(c => c + 1) reliable even when several increments are queued from the same event.

Question 35IntermediateCode Output

After one click, what value does this counter display?

Direct answer

After one click, the counter displays 1 because all three calls calculate the replacement value from the same count snapshot.

Counter.jsx
function Counter() {
  const [count, setCount] = useState(0);

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

  return <button onClick={handleClick}>{count}</button>;
}
Output
After one click:
1

During this handler, count is still 0. Each call therefore queues a request equivalent to replacing the state with 1, rather than adding three independent increments.

Question 36IntermediateCode Output

After one click, what value does this counter display when updater functions are used?

Direct answer

After one click, the counter displays 3 because React applies each queued updater to the result of the previous updater.

Counter.jsx
function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(c => c + 1);
    setCount(c => c + 1);
    setCount(c => c + 1);
  }

  return <button onClick={handleClick}>{count}</button>;
}
Output
After one click:
3

React processes the updater queue in order: 0 becomes 1, then 2, then 3. Updater functions should be pure because React may call them more than once in development to detect mistakes.

Question 37IntermediatePractical

How should you update objects and arrays stored in React state?

Direct answer

Create a new object or array that contains the desired changes instead of mutating the existing state value.

Profile.jsx
function Profile() {
  const [user, setUser] = useState({
    name: "Ava",
    skills: ["React"]
  });

  function addSkill() {
    setUser(current => ({
      ...current,
      skills: [...current.skills, "TypeScript"]
    }));
  }

  return <button onClick={addSkill}>{user.skills.length}</button>;
}
  • Objects: use object spread or another immutable transformation to create a new reference.
  • Arrays: prefer methods such as map, filter, concat, or spread instead of mutating methods such as push or splice on state.
  • Nested data: copy every changed level, or use an abstraction such as Immer if the state shape makes immutable updates cumbersome.
Question 38IntermediateConcept

Why should you avoid storing redundant or derived data in React state?

Direct answer

If a value can be calculated from current props or state during render, storing another copy usually creates synchronization bugs and unnecessary updates.

Cart.jsx
function Cart({ items }) {
  // Prefer deriving this during render:
  const total = items.reduce((sum, item) => sum + item.price, 0);

  return <strong>Total: {total}</strong>;
}

Two state variables that represent the same underlying fact can drift apart. A useful rule is to store the minimal source of truth and derive the rest during rendering.

Question 39IntermediateComparison

What is the difference between useState and useReducer, and when would you choose each?

Direct answer

useState is usually simpler for independent state values, while useReducer is useful when several related updates form a state transition model that is easier to express with actions.

ConcernuseStateuseReducer
Update APICall a setter with the next value/updaterDispatch an action
Best fitSimple or independent stateRelated state with multiple transition rules
Update logicOften lives near event handlersCentralized in a reducer
Debugging intentSetter shows value changeAction can describe what happened

A reducer does not make state global. useReducer() still manages state for the component instance unless you deliberately expose it through props or context.

Question 40IntermediateConcept

What makes a well-designed reducer in React?

Direct answer

A reducer should be a pure function that receives the current state and an action, then returns the next state without mutating the previous state or performing side effects.

tasksReducer.js
function tasksReducer(state, action) {
  switch (action.type) {
    case "added":
      return [
        ...state,
        { id: action.id, text: action.text, done: false }
      ];
    case "toggled":
      return state.map(task =>
        task.id === action.id
          ? { ...task, done: !task.done }
          : task
      );
    default:
      return state;
  }
}
  • Pure transition: same state + action should produce the same next state.
  • No side effects: API calls, analytics, timers, and DOM work belong outside the reducer.
  • Action intent: actions should describe meaningful events such as added or toggled rather than hide arbitrary mutations.
Question 41IntermediateConcept

What is a custom Hook in React, and when should you create one?

Direct answer

A custom Hook is a function whose name starts with use and that can call other Hooks to package reusable stateful or synchronization logic.

useOnlineStatus.js
function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);

  useEffect(() => {
    const online = () => setIsOnline(true);
    const offline = () => setIsOnline(false);

    window.addEventListener("online", online);
    window.addEventListener("offline", offline);

    return () => {
      window.removeEventListener("online", online);
      window.removeEventListener("offline", offline);
    };
  }, []);

  return isOnline;
}

Custom Hooks let components reuse logic without introducing another visual component into the tree.

Question 42IntermediateConcept

Do two components using the same custom Hook share the same state?

Direct answer

No. A custom Hook shares reusable logic, but every component call receives its own Hook state unless that state is connected through a shared external source or context.

Calling the same custom Hook twice behaves like calling built-in Hooks twice: each call belongs to the component instance and has its own state slots.

Shared automatically
The Hook implementation and behavior
Not shared automatically
useState/useReducer state created by each Hook call
Can be shared deliberately
Context, an external store, URL state, server cache, or another shared data source
Question 43IntermediateConcept

How should you think about the lifecycle and cleanup of a React Effect?

Direct answer

An Effect starts synchronizing with an external system after a commit, and its cleanup stops the previous synchronization before React starts it again or removes the component.

ChatRoom.jsx
function ChatRoom({ roomId }) {
  useEffect(() => {
    const connection = createConnection(roomId);
    connection.connect();

    return () => {
      connection.disconnect();
    };
  }, [roomId]);

  return <h1>{roomId}</h1>;
}
  1. The component commits with the current roomId.
  2. The Effect starts the connection for that room.
  3. If roomId changes, React runs the previous cleanup.
  4. React starts the Effect again using the new roomId.
  5. When the component is removed, cleanup runs for the active synchronization.
Question 44IntermediateConcept

How does the dependency array of useEffect actually work?

Direct answer

The dependency array must include every reactive value read by the Effect; React re-synchronizes when any dependency changes according to Object.is comparison.

Props, state, and values calculated inside the component are reactive values because they can change between renders. If an Effect reads them, they generally belong in its dependency list.

No dependency array
Effect is eligible to run after every commit
Empty array []
Effect has no reactive dependencies
[a, b]
Effect re-synchronizes when a or b changes
Question 45IntermediateScenario

What is a stale closure bug in a React Effect, and how would you fix it?

Direct answer

A stale closure occurs when an Effect or callback keeps using values captured by an older render because its synchronization logic does not track the values it actually depends on.

Counter.jsx
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      console.log(count);
    }, 1000);

    return () => clearInterval(id);
  }, []); // count is read but omitted

  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

The interval callback was created by the render where count had its old value. Possible fixes depend on the intent: include the reactive dependency, use an updater when updating state from previous state, or use an Effect Event when the logic should read the latest value without re-synchronizing the external subscription.

Question 46IntermediateConcept

What problem does useEffectEvent solve in modern React?

Direct answer

useEffectEvent lets Effect logic read the latest committed props and state without making that non-reactive logic a reason for the Effect itself to re-synchronize.

ChatRoom.jsx
function ChatRoom({ roomId, muted }) {
  const onConnected = useEffectEvent(() => {
    if (!muted) {
      showNotification("Connected");
    }
  });

  useEffect(() => {
    const connection = createConnection(roomId);
    connection.on("connected", onConnected);
    connection.connect();

    return () => connection.disconnect();
  }, [roomId]);

  return <h1>{roomId}</h1>;
}

The connection is reactive to roomId, but the notification can read the latest muted value without reconnecting merely because the preference changed.

Question 47IntermediateComparison

What is the difference between putting logic in an event handler and putting it in an Effect?

Direct answer

Event handlers run because a specific interaction occurred, while Effects run because rendered state must synchronize with an external system.

QuestionEvent handlerEffect
Why does it run?A particular interaction happenedSynchronization is required after rendering
Typical exampleSubmit order after button clickConnect to a room while roomId is active
Reactive?No; runs only for the interactionYes; re-synchronizes when dependencies change
Common mistakePutting synchronization here that should follow rendered statePutting interaction-specific actions here

If sending a POST request should happen because the user clicked Submit, keep it in the submit handler. If a connection should exist whenever a particular roomId is rendered, an Effect expresses that synchronization.

Question 48IntermediateComparison

What is the difference between useEffect and useLayoutEffect?

Direct answer

useEffect is the default choice for synchronizing with external systems, while useLayoutEffect runs earlier around layout and can block painting, so it is reserved for work that must measure or adjust layout before the user sees it.

ConcernuseEffectuseLayoutEffect
Primary useExternal synchronizationLayout measurement or visual adjustment
PaintingUsually lets the browser paint firstRuns before the browser repaints
CostDoes not normally block paintCan block paint and hurt performance
Default choiceYesOnly when visual timing requires it
Tooltip.jsx
function Tooltip() {
  const ref = useRef(null);

  useLayoutEffect(() => {
    const rect = ref.current.getBoundingClientRect();
    // Measure before the browser paints the final position.
    positionTooltip(rect);
  }, []);

  return <div ref={ref}>Tooltip</div>;
}
Question 49IntermediateConcept

Why can components, Effects, and ref callbacks appear to run twice in React Strict Mode?

Direct answer

Strict Mode performs extra development-only checks, including extra rendering and setup/cleanup cycles, to expose impure rendering and missing cleanup before those bugs reach production.

  • Render checks: pure component logic may be invoked an extra time in development.
  • Effect checks: React can run an extra setup -> cleanup -> setup cycle to expose missing cleanup.
  • Ref callback checks: callback refs can also receive extra setup/cleanup checks.
  • Production: these Strict Mode checks do not add the same duplicate behavior to the production build.

The goal is not to make developers add flags such as didRun.current to suppress the second call. The goal is to make rendering pure and synchronization cleanup correct.

Question 50IntermediateConcept

How does React decide whether to preserve or reset component state?

Direct answer

React associates state with a component's position and identity in the render tree; changing the component type or its key can make React treat it as a different component and reset that state.

Messenger.jsx
function Messenger({ contact }) {
  return (
    <Chat
      key={contact.id}
      contact={contact}
    />
  );
}

Using key outside lists is sometimes useful when changing business identity should deliberately create a fresh component instance—for example, clearing a message draft when switching recipients.

Question 51IntermediateScenario

Why can defining a component inside another component accidentally reset state?

Direct answer

A nested component definition creates a new component function on every parent render, so React can treat the child as a different component type and recreate its subtree.

Parent.jsx
function Parent() {
  const [count, setCount] = useState(0);

  // Avoid defining component types here.
  function Form() {
    const [text, setText] = useState("");
    return <input value={text} onChange={e => setText(e.target.value)} />;
  }

  return (
    <>
      <button onClick={() => setCount(c => c + 1)}>{count}</button>
      <Form />
    </>
  );
}

Move Form to module scope so its component type remains stable across Parent renders.

Question 52IntermediateConcept

What does React.memo do, and what does it not prevent?

Direct answer

memo can skip a child render when its parent re-renders and the child's props are unchanged, but it does not block renders caused by the child's own state or context changes.

Row.jsx
const Row = memo(function Row({ item }) {
  return <li>{item.name}</li>;
});
  • Can skip: a parent-driven render when props compare equal.
  • Cannot skip: updates caused by the memoized component's own state.
  • Cannot skip: updates from context values that the component reads.
  • Requirement: rendering must already be pure; memo is an optimization, not a correctness tool.
Question 53IntermediateConcept

What does useMemo do, and when is it actually useful?

Direct answer

useMemo caches the result of a pure calculation between renders while its dependencies remain equal, and it should be treated as a performance optimization rather than part of application correctness.

ProductList.jsx
function ProductList({ products, query }) {
  const visibleProducts = useMemo(
    () => expensiveFilter(products, query),
    [products, query]
  );

  return <Results items={visibleProducts} />;
}
  • Expensive calculation: avoid recomputing work when its inputs rarely change.
  • Stable prop value: preserve an object/array identity passed to a memoized child when that stability actually matters.
  • Hook dependency: preserve a value whose identity is intentionally used by another Hook.
Question 54IntermediateConcept

What does useCallback do, and when is it useful?

Direct answer

useCallback caches a function definition between renders while its dependencies remain unchanged, mainly when function identity affects a memoized child or another Hook.

ProductPage.jsx
function ProductPage({ productId }) {
  const handleBuy = useCallback(() => {
    purchase(productId);
  }, [productId]);

  return <MemoizedBuyButton onBuy={handleBuy} />;
}

Creating a new JavaScript function is usually cheap. The benefit comes when a stable function identity prevents downstream work such as re-rendering a memoized child or re-synchronizing an Effect.

Question 55IntermediateComparison

What is the difference between memo, useMemo, and useCallback?

Direct answer

memo memoizes a component against unchanged props, useMemo caches a calculated value, and useCallback caches a function definition.

APIWhat it cachesTypical reason
memoComponent render result based on propsSkip parent-driven child renders
useMemoResult of a calculationSkip expensive recalculation or stabilize a value
useCallbackFunction definitionStabilize callback identity for a consumer

All three are performance tools. Code should remain correct if the optimization is removed.

Question 56IntermediateScenario

A child is wrapped in memo but still re-renders every time its parent renders. What would you inspect first?

Direct answer

Inspect whether the parent creates new object, array, or function props on every render, because new references can make props compare as changed even when their contents look equivalent.

Search.jsx
const Results = memo(function Results({ options }) {
  return <pre>{JSON.stringify(options)}</pre>;
});

function Search({ query }) {
  // New object on every render:
  const options = { query, limit: 20 };

  return <Results options={options} />;
}
  • First: confirm the re-render is actually expensive with profiling.
  • Then: inspect prop identities and whether the child also reads changing context or has its own state.
  • If necessary: restructure props, memoize a meaningful value, or rely on React Compiler when enabled.
Question 57IntermediateConcept

How does React Compiler change the way you think about memo, useMemo, and useCallback?

Direct answer

React Compiler can automatically memoize components and calculations at build time, reducing the amount of manual memoization needed in compiler-enabled applications.

The compiler analyzes components and Hooks under the Rules of React and can generate memoization that skips unnecessary cascading renders and repeated calculations.

  • New compiler-enabled code: prefer clear React code first and rely on automatic memoization where appropriate.
  • Existing manual memoization: do not delete it blindly; removal can change compilation output or performance behavior.
  • Escape hatch: useMemo and useCallback still exist when you need precise control, especially around identity-sensitive dependencies.
Question 58IntermediateScenario

What performance pitfalls can occur with React Context?

Direct answer

When a provider value changes, components that read that context update; large, frequently changing context values can therefore create broad re-render fan-out.

AppProvider.jsx
function AppProvider({ children }) {
  const [user, setUser] = useState(null);

  const value = { user, setUser };

  return (
    <AuthContext value={value}>
      {children}
    </AuthContext>
  );
}
  • Provider value identity: a newly created object can represent a changed context value on each provider render.
  • Large contexts: unrelated consumers may update together when one field changes.
  • Design options: keep providers focused, split independent contexts, separate state from dispatch when useful, and profile before adding memoization.
Question 59IntermediateComparison

When should you use Context instead of props or component composition?

Direct answer

Use props for explicit local data flow, composition when intermediate components only need to pass UI through, and Context when distant descendants genuinely need the same ambient value.

TechniqueBest fitTrade-off
PropsExplicit parent-to-child data flowCan become repetitive across deep trees
Composition / childrenLet a parent supply UI without threading every data propDoes not solve every shared-data case
ContextAmbient data needed by many distant descendantsCreates an implicit dependency and can broaden updates

Common Context examples include theme, current account, routing-like ambient data, and shared state for a subtree. But prop drilling alone is not proof that every value belongs in Context.

Question 60IntermediatePractical

How can useReducer and Context work together for a complex screen?

Direct answer

A component can own state with useReducer and provide the state and dispatch through Context so distant descendants can read or update the same reducer-managed screen state.

TasksProvider.jsx
const TasksContext = createContext(null);
const TasksDispatchContext = createContext(null);

function TasksProvider({ children }) {
  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);

  return (
    <TasksContext value={tasks}>
      <TasksDispatchContext value={dispatch}>
        {children}
      </TasksDispatchContext>
    </TasksContext>
  );
}

Splitting state context from dispatch context can make dependencies clearer and lets components that only dispatch avoid reading the state value.

Question 61IntermediateConcept

What is useId used for in React?

Direct answer

useId generates a stable identifier that is useful for connecting accessibility attributes such as a label to an input across client and server rendering.

PasswordField.jsx
function PasswordField() {
  const hintId = useId();

  return (
    <>
      <input
        type="password"
        aria-describedby={hintId}
      />
      <p id={hintId}>Use at least 12 characters.</p>
    </>
  );
}

The main use case is accessibility relationships and generated IDs that need to be safe across React's rendering model.

Question 62IntermediateComparison

How did ref handling for function components change in React 19 compared with older React versions?

Direct answer

In React 19, function components can receive ref as a prop directly; older React versions typically required forwardRef to expose a ref through a function component.

Version styleTypical function component ref pattern
React 19+Receive ref as a prop and pass/customize it
React 18 and earlierWrap the component with forwardRef
MyInput.jsx
function MyInput({ ref, ...props }) {
  return <input {...props} ref={ref} />;
}

function Form() {
  const inputRef = useRef(null);

  return (
    <>
      <MyInput ref={inputRef} />
      <button onClick={() => inputRef.current?.focus()}>
        Focus
      </button>
    </>
  );
}
Question 63IntermediatePractical

When would you use useImperativeHandle in React?

Direct answer

Use useImperativeHandle when a component must expose a small, intentional imperative API through a ref instead of exposing its entire DOM node or internal implementation.

SearchInput.jsx
function SearchInput({ ref }) {
  const inputRef = useRef(null);

  useImperativeHandle(ref, () => ({
    focus() {
      inputRef.current?.focus();
    },
    select() {
      inputRef.current?.select();
    }
  }), []);

  return <input ref={inputRef} />;
}
  • Good fit: focus, scrolling, text selection, imperative animation, or integration with non-React APIs.
  • Prefer props: when the behavior can be expressed declaratively, such as isOpen, value, or selected.
Question 64IntermediateConcept

What is a React portal, and when would you use one?

Direct answer

A portal renders React children into a different DOM node while keeping those children connected to their original React tree for context and event propagation.

Modal.jsx
function Modal({ children }) {
  return createPortal(
    <div className="modal">{children}</div>,
    document.body
  );
}
  • Typical uses: modals, dialogs, tooltips, overlays, and integration with DOM containers outside the normal parent element.
  • React relationship: the portal child still receives context from its React ancestors.
  • Physical DOM: only the DOM placement changes.
Question 65IntermediateScenario

A click inside a modal portal triggers an onClick handler on a React ancestor outside the portal's DOM container. Why?

Direct answer

Events from a portal propagate according to the React tree, so a React ancestor can receive the event even when the portal's DOM node is physically elsewhere.

App.jsx
function App() {
  return (
    <div onClick={() => console.log("App clicked")}>
      <Modal>
        <button>Save</button>
      </Modal>
    </div>
  );
}

The button may be rendered under document.body in the DOM, but it is still a child of App in the React tree.

Question 66IntermediateConcept

How does React.lazy support code splitting?

Direct answer

lazy defers loading a component's module until React first needs to render that component, allowing its code to be loaded on demand.

Editor.jsx
const MarkdownPreview = lazy(
  () => import("./MarkdownPreview.jsx")
);

function Editor() {
  return (
    <Suspense fallback={<Spinner />}>
      <MarkdownPreview />
    </Suspense>
  );
}

The lazy component suspends while its module is loading, so a surrounding Suspense boundary can render fallback UI.

Question 67IntermediateConcept

What does a Suspense boundary do when one of its children suspends?

Direct answer

Suspense shows its fallback while content inside the boundary is not ready, then reveals the real content when the suspended work becomes ready.

Page.jsx
function Page() {
  return (
    <Suspense fallback={<ArticleSkeleton />}>
      <Article />
    </Suspense>
  );
}
  • Code loading: a component declared with lazy can activate the boundary while its module loads.
  • Suspense-enabled data: supported framework/data mechanisms can also suspend during rendering.
  • Boundary placement: determines how much of the interface is replaced or revealed together.
Question 68IntermediateComparison

What is the difference between Suspense and an Error Boundary?

Direct answer

Suspense handles content that is temporarily not ready, while an Error Boundary handles supported errors thrown by descendant rendering and displays fallback error UI.

ConcernSuspenseError Boundary
Primary conditionContent is waiting / suspendedDescendant rendering throws an error
Fallback meaningLoading or pending UIFailure UI
Typical pairinglazy or Suspense-enabled dataError recovery/logging boundary
Same thing?NoNo

A lazy import that is still loading is handled by Suspense. If that lazy import's loading promise rejects, the error can be handled by the nearest Error Boundary.

Question 69IntermediateConcept

What is an Error Boundary in React, and what errors does it handle?

Direct answer

An Error Boundary is a React component that catches supported errors from descendant rendering, shows fallback UI, and can log the failure instead of letting that part of the UI disappear.

ErrorBoundary.jsx
class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    reportError(error, info);
  }

  render() {
    if (this.state.hasError) {
      return <Fallback />;
    }
    return this.props.children;
  }
}

React's built-in class lifecycle APIs getDerivedStateFromError and componentDidCatch are the traditional primitives for implementing an Error Boundary.

Question 70IntermediateScenario

A component fetches data when an ID changes, but a slower old request sometimes overwrites the result of a newer request. How would you fix it?

Direct answer

Make the Effect cleanup invalidate or cancel work from the previous ID so an obsolete request cannot commit stale data after the component has synchronized to a newer ID.

UserProfile.jsx
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    const controller = new AbortController();

    async function load() {
      try {
        const response = await fetch(
          `/api/users/${userId}`,
          { signal: controller.signal }
        );
        const data = await response.json();
        setUser(data);
      } catch (error) {
        if (error.name !== "AbortError") {
          throw error;
        }
      }
    }

    load();
    return () => controller.abort();
  }, [userId]);

  return <Profile user={user} />;
}

When userId changes, cleanup aborts the previous request before the Effect starts synchronization for the new ID. Another valid pattern is to mark the old request as ignored if the underlying API cannot be cancelled.

3

Advanced React Interview Questions

Question 71AdvancedConcept

What does concurrent rendering mean in React?

Direct answer

Concurrent rendering means React can prioritize, pause, resume, restart, or abandon render work before committing it, allowing urgent interactions to stay responsive while lower-priority UI is prepared.

The important property is that rendering can be interruptible. React may begin calculating a new tree, pause that work when something more urgent arrives, and continue or restart later.

  • Render phase: React calculates what the UI should look like and may interrupt this work.
  • Commit phase: React applies the finished result to the host environment; it does not commit a half-finished tree.
  • User experience: urgent input can remain responsive while expensive non-urgent UI is prepared in the background.
Question 72AdvancedConcept

What does useTransition do in React?

Direct answer

useTransition lets a component mark selected state updates as non-blocking Transitions and exposes an isPending flag while that Transition is still in progress.

Tabs.jsx
function Tabs() {
  const [tab, setTab] = useState("overview");
  const [isPending, startTransition] = useTransition();

  function selectTab(nextTab) {
    startTransition(() => {
      setTab(nextTab);
    });
  }

  return (
    <>
      <TabButtons onSelect={selectTab} />
      {isPending && <span>Updating…</span>}
      <TabContent tab={tab} />
    </>
  );
}

The update inside startTransition() is treated as non-urgent, so React can interrupt it to handle more urgent work such as typing or another interaction.

Question 73AdvancedCode Output

What is the console output, and does startTransition delay its callback?

Direct answer

The output is Before, Inside, After because startTransition calls its action immediately; it marks qualifying state updates inside that call as Transitions rather than delaying ordinary JavaScript execution.

transition-order.js
console.log("Before");

startTransition(() => {
  console.log("Inside");
});

console.log("After");
Output
Before
Inside
After

The function passed to startTransition() runs immediately. React's special behavior applies to state updates scheduled during that call, not to the execution timing of normal statements like console.log().

Question 74AdvancedComparison

What is the difference between useTransition and startTransition?

Direct answer

Both mark updates as Transitions, but useTransition also provides isPending and is available only inside React components or custom Hooks, while standalone startTransition can be called from other JavaScript modules.

ConcernuseTransitionstartTransition
Where usedComponents and custom HooksComponents or non-component code
Marks updates as TransitionYesYes
Pending indicatorProvides isPendingNo built-in pending flag
Typical useUI that needs pending feedbackLibraries or code that only needs to mark priority

If a component needs to dim a tab, disable navigation controls, or show inline pending feedback, useTransition() is usually more convenient.

Question 75AdvancedScenario

Why should a controlled text input's value update not be placed inside a Transition?

Direct answer

Controlled input state must update synchronously with the user's typing; instead, update the input state urgently and defer the expensive UI that depends on it.

SearchPage.jsx
function SearchPage() {
  const [query, setQuery] = useState("");
  const [resultsQuery, setResultsQuery] = useState("");
  const [isPending, startTransition] = useTransition();

  function handleChange(event) {
    const nextQuery = event.target.value;

    setQuery(nextQuery); // urgent: controls the input

    startTransition(() => {
      setResultsQuery(nextQuery); // non-urgent
    });
  }

  return (
    <>
      <input value={query} onChange={handleChange} />
      <Results query={resultsQuery} />
    </>
  );
}

React requires the state controlling the input's value to track each keystroke immediately. The expensive result view is the part that can be deprioritized.

Question 76AdvancedComparison

How is useDeferredValue different from debouncing and throttling?

Direct answer

useDeferredValue deprioritizes rendering of a value with React's scheduler and has no fixed delay, while debouncing and throttling are time-based techniques that control how often work is triggered.

TechniqueWhat it controlsFixed time window?Typical goal
useDeferredValuePriority of rendering derived UINoKeep urgent UI responsive
DebounceWhen an operation is invoked after activity stopsUsually yesReduce calls such as search requests
ThrottleMaximum invocation frequencyUsually yesLimit high-frequency handlers

A deferred value may lag behind the current value while React renders the newer version in the background. It does not automatically reduce network requests.

Question 77AdvancedConcept

How do Transitions interact with Suspense when already visible content suspends again?

Direct answer

When a non-urgent Transition causes already revealed content to suspend, React can keep the existing content visible instead of immediately replacing it with the nearest Suspense fallback.

Router.jsx
function Router() {
  const [page, setPage] = useState("/");

  function navigate(nextPage) {
    startTransition(() => {
      setPage(nextPage);
    });
  }

  return (
    <Suspense fallback={<FullPageSpinner />}>
      <Page page={page} navigate={navigate} />
    </Suspense>
  );
}
  • Urgent update: if visible content suspends, the closest boundary may show its fallback immediately.
  • Transition update: React can keep already revealed content visible while preparing the replacement.
  • New nested boundaries: newly introduced Suspense boundaries may still show their own fallbacks rather than blocking the whole transition.
Question 78AdvancedConcept

What does the React use API do, and how is it different from ordinary Hooks?

Direct answer

use reads a resource such as a Promise or Context value; reading a pending Promise suspends the component, and unlike Hooks such as useState, use can be called inside loops and conditionals.

Comments.jsx
function Comments({ commentsPromise, show }) {
  if (!show) {
    return null;
  }

  const comments = use(commentsPromise);

  return comments.map(comment => (
    <p key={comment.id}>{comment.text}</p>
  ));
}
  • Promise: a pending Promise suspends; a resolved Promise provides its value; a rejection propagates to error handling.
  • Context: use can read the nearest Context value similarly to useContext.
  • Calling rules: use must still be called from a Component or Hook, but it may appear conditionally or in loops.
Question 79AdvancedScenario

Why must Promises passed to React use be cached or reused across renders?

Direct answer

Creating a fresh Promise during every render gives React a different resource each time, which can cause repeated suspension; use a cached Promise, framework data source, or Promise passed from a Server Component.

Albums.jsx
function Albums() {
  // Avoid: a new Promise is created every render.
  const albums = use(fetch("/api/albums"));

  return <AlbumList albums={albums} />;
}

The component needs a stable resource identity so React can retry rendering against the same asynchronous work instead of continuously discovering a brand-new pending Promise.

Question 80AdvancedConcept

What is an Action in modern React?

Direct answer

An Action is a function invoked within a Transition to perform work such as an asynchronous mutation while React coordinates pending state, optimistic UI, errors, and related rendering.

RenameButton.jsx
function RenameButton({ saveName }) {
  const [isPending, startTransition] = useTransition();

  function rename() {
    startTransition(async () => {
      await saveName("Ada");
    });
  }

  return (
    <button disabled={isPending} onClick={rename}>
      Rename
    </button>
  );
}

Modern React APIs such as useActionState() and useOptimistic() are designed to compose around this Action model.

Question 81AdvancedComparison

How is useActionState different from useReducer?

Direct answer

useReducer manages pure UI state transitions, while useActionState manages the result and pending state of Actions and its reducer action may be asynchronous and perform side effects.

ConcernuseReduceruseActionState
Reducer purityMust be pureReducer action may perform side effects
Async workKeep outside reducerReducer action may be async
Pending stateBuild separatelyBuilt-in isPending
Dispatch behaviorUI state transitionsAction calls are queued sequentially

Because useActionState() passes the previous action result into the next action, multiple dispatched Actions are processed in order rather than being a generic parallel-task primitive.

Question 82AdvancedConcept

How does useOptimistic work, and what happens when an Action fails?

Direct answer

useOptimistic temporarily renders an expected state while an Action is pending; when the Action finishes the UI converges to the real value, and if the mutation fails the optimistic state disappears unless the canonical value was changed.

LikeButton.jsx
function LikeButton({ liked, saveLike }) {
  const [optimisticLiked, setOptimisticLiked] =
    useOptimistic(liked);

  function handleClick() {
    startTransition(async () => {
      setOptimisticLiked(true);
      await saveLike();
    });
  }

  return (
    <button onClick={handleClick}>
      {optimisticLiked ? "Liked" : "Like"}
    </button>
  );
}
  • Immediate feedback: optimistic state can appear before the server confirms the mutation.
  • Canonical value: the normal value remains the source that determines what survives after the Action.
  • Failure: if the Action fails and the canonical value never updates, React returns to that canonical value after the Action ends.
Question 83AdvancedConcept

How does useFormStatus determine whether a form submission is pending?

Direct answer

useFormStatus reads submission status from the nearest parent form, so the component calling it must be rendered inside that form rather than in the same component that creates the form element.

SettingsForm.jsx
function SubmitButton() {
  const { pending } = useFormStatus();

  return (
    <button type="submit" disabled={pending}>
      {pending ? "Saving…" : "Save"}
    </button>
  );
}

function SettingsForm({ action }) {
  return (
    <form action={action}>
      <input name="displayName" />
      <SubmitButton />
    </form>
  );
}

The status object can expose pending, submitted data, the form method, and the active action.

Question 84AdvancedConcept

Why does React provide useSyncExternalStore instead of recommending a normal Effect subscription for external stores?

Direct answer

useSyncExternalStore gives React a consistent snapshot-and-subscribe contract for mutable data outside React, including correct integration with concurrent rendering and server rendering.

useOnlineStatus.js
function useOnlineStatus() {
  return useSyncExternalStore(
    subscribe,
    getSnapshot,
    getServerSnapshot
  );
}

function getSnapshot() {
  return navigator.onLine;
}

function subscribe(callback) {
  window.addEventListener("online", callback);
  window.addEventListener("offline", callback);

  return () => {
    window.removeEventListener("online", callback);
    window.removeEventListener("offline", callback);
  };
}
  • subscribe: tells React how to listen for store changes and clean up.
  • getSnapshot: returns the current immutable snapshot React should render.
  • getServerSnapshot: optionally provides the initial server/hydration snapshot.
Question 85AdvancedScenario

What bugs occur if getSnapshot in useSyncExternalStore returns a new object every time?

Direct answer

If getSnapshot always returns a new reference even when the store has not changed, React can repeatedly treat the snapshot as changed and enter unnecessary or even infinite re-rendering.

store.js
function getSnapshot() {
  // Wrong: a fresh object every call.
  return {
    todos: store.todos
  };
}
  • Stable when unchanged: repeated reads must return the same value while the store has not changed.
  • Immutable snapshot: if the underlying store mutates objects, cache an immutable snapshot and only replace it after a real change.
  • SSR: getServerSnapshot must produce data that matches the initial client hydration snapshot.
Question 86AdvancedComparison

What is the difference between createRoot and hydrateRoot?

Direct answer

createRoot renders React into a client-owned DOM container, while hydrateRoot attaches React behavior to HTML that was already rendered on the server and is expected to match the client's initial output.

ConcerncreateRoothydrateRoot
Starting DOMContainer is rendered by the client rootContains server-rendered React HTML
Primary purposeClient renderingHydration of server-rendered markup
Markup matching requirementNo server markup contractInitial client output must match server HTML
Typical framework usePure client entrySSR/streamed application entry

Hydration is not simply 'render React again'. React attempts to attach event handling and component behavior to the existing server-generated structure.

Question 87AdvancedScenario

What causes hydration mismatches, and how should you debug them?

Direct answer

A hydration mismatch occurs when the client's initial render does not produce the same structure or text as the server HTML, so debug the first render for environment-dependent or nondeterministic output rather than treating the warning as cosmetic.

  • Nondeterministic values: timestamps, random numbers, locale differences, or unstable IDs generated independently on server and client.
  • Browser-only branching: rendering different JSX because window, localStorage, or viewport data exists only on the client.
  • Data mismatch: the client hydrates using different initial data from the data used to generate server HTML.
  • Invalid markup: browser HTML correction can change the DOM structure before React hydrates it.

Prefer making the initial server and client outputs identical. If something truly cannot match, isolate the difference instead of broadly suppressing hydration warnings.

Question 88AdvancedConcept

What is selective hydration, and how do Suspense boundaries help?

Direct answer

Selective hydration lets React hydrate server-rendered UI in independent pieces so important interactions can become usable before every part of the page has finished loading or hydrating.

Suspense boundaries naturally divide the tree into independent hydration units. React can prioritize the pieces needed for visible or user-interacted content instead of treating the page as one all-or-nothing hydration task.

  • Server HTML: content can be visible before all client JavaScript is ready.
  • Priority: React can focus hydration work on areas that matter to the user first.
  • Architecture: Suspense placement therefore affects both loading UX and hydration granularity.
Question 89AdvancedComparison

What is the difference between React Server Components and traditional server-side rendering?

Direct answer

SSR generates initial HTML for components that may later hydrate on the client, while Server Components execute outside the client bundle and send rendered component output that does not itself become interactive client component code.

ConcernServer-Side RenderingServer Components
Main goalGenerate initial HTMLKeep selected component logic and dependencies off the client
Client JavaScriptRendered components may still hydrateServer Component implementation is not shipped as client component code
Data accessServer rendering can fetch dataServer Components can directly access server-side data during their render
InteractivityHydrated components can be interactiveInteractivity is composed using Client Components

The two technologies can be combined. A framework can render a Server Component tree and also use SSR to produce initial HTML for the overall page.

Question 90AdvancedComparison

What capabilities distinguish Server Components from Client Components?

Direct answer

Server Components can run server-only code and async rendering without shipping their implementation to the browser, while Client Components can use interactive state, Effects, event handlers, and browser APIs.

CapabilityServer ComponentClient Component
Direct server data accessYesUsually through a server interface/framework
useState / interactive HooksNoYes
Event handlersNoYes
Browser APIsNoYes
Async component functionSupportedNot the normal Client Component model
Implementation shipped to browserNoYes

A common architecture keeps data-heavy, non-interactive regions on the server and introduces Client Component islands only where interaction is needed.

Question 91AdvancedConcept

What does the 'use client' directive actually mark?

Direct answer

'use client' marks a module as a Client Component boundary so that it and the client-side dependency graph reachable from that boundary can participate in browser execution.

Counter.jsx
"use client";

import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(c => c + 1)}>
      {count}
    </button>
  );
}

You do not need to put "use client" in every component file. It defines a boundary; modules imported through that client graph are handled as client-side code by an RSC-compatible bundler.

Question 92AdvancedConcept

What are React Server Functions, and what does 'use server' mean?

Direct answer

Server Functions are async functions executed on the server that can be referenced from client-side code; 'use server' marks such a server function or module for an RSC-compatible framework.

actions.js
export async function updateProfile(formData) {
  "use server";

  const name = formData.get("name");
  await db.profile.update({ name });
}

Calling a Server Function from client code involves a network request with serialized arguments and a serialized result. Framework integration creates the client reference and transport.

Question 93AdvancedScenario

Why must every Server Function perform its own validation and authorization?

Direct answer

Server Function arguments are client-controlled network input, so the function must validate data and verify that the authenticated user is authorized to perform the requested mutation.

project-actions.js
export async function deleteProject(projectId) {
  "use server";

  const user = await requireUser();

  const project = await db.project.find(projectId);

  if (!project || project.ownerId !== user.id) {
    throw new Error("Not authorized");
  }

  await db.project.delete(projectId);
}

Do

  • Authenticate the caller on the server
  • Authorize access to the specific resource
  • Validate and normalize all submitted data
  • Return only data that is safe to serialize to the client

Don't

  • Trust a hidden form field as proof of ownership
  • Assume a function is private because the UI hides its button
  • Treat TypeScript types as runtime validation
Question 94AdvancedConcept

Why do values crossing a Server Component to Client Component boundary need to be serializable?

Direct answer

React must encode values crossing the server/client boundary into the transport format, so props must use supported serializable values rather than arbitrary local functions, class instances, or non-serializable runtime objects.

  • Commonly safe: strings, numbers, booleans, null, supported plain data structures, and other values explicitly supported by the RSC serialization contract.
  • Functions: ordinary local functions cannot cross the boundary; Server Functions are the special supported function case.
  • Design impact: shape server data into client-facing DTO-like values rather than passing arbitrary server objects through the boundary.

This boundary is also useful architecturally: it forces the client-facing contract to be explicit instead of accidentally leaking server implementation details.

Question 95AdvancedComparison

What does React cache do in Server Components, and how is it different from useMemo?

Direct answer

React cache memoizes a function's result for use during Server Component rendering so work can be shared across components in a server request, while useMemo caches one component's calculation between client renders based on dependencies.

ConcerncacheuseMemo
Primary environmentServer ComponentsComponent rendering
Sharing scopeCan share memoized work across Server Components in a requestBelongs to a component instance/render lifecycle
Good for data fetchesYesNo; useMemo is for pure calculations
Invalidation modelReact invalidates server cache across requestsRecomputes when dependencies change
profile.jsx
import { cache } from "react";

const getUser = cache(async (id) => {
  return db.user.find(id);
});

async function Avatar({ userId }) {
  const user = await getUser(userId);
  return <img src={user.avatarUrl} alt="" />;
}

async function ProfileName({ userId }) {
  const user = await getUser(userId);
  return <h1>{user.name}</h1>;
}
Question 96AdvancedConcept

What does the Activity component introduced in React 19.2 solve?

Direct answer

Activity lets React hide UI while preserving its internal state, clean up its Effects, and deprioritize hidden updates so the content can be restored or pre-rendered efficiently.

App.jsx
function App({ activeTab }) {
  return (
    <>
      <Activity mode={activeTab === "home" ? "visible" : "hidden"}>
        <Home />
      </Activity>

      <Activity mode={activeTab === "posts" ? "visible" : "hidden"}>
        <Posts />
      </Activity>
    </>
  );
}
  • Preserve state: hidden content can return with previous local state intact.
  • Clean Effects: Effects are cleaned up while the Activity is hidden and re-created when visible.
  • Background preparation: hidden content can still be rendered at lower priority so code/data may be ready before reveal.
Question 97AdvancedScenario

A video keeps playing after its Activity becomes hidden. Why can that happen?

Direct answer

Hidden Activity content keeps its DOM rather than destroying it, so intrinsic DOM behavior such as an already-playing video can continue unless your component explicitly stops it during Effect cleanup.

VideoPlayer.jsx
function VideoPlayer({ src }) {
  const ref = useRef(null);

  useEffect(() => {
    const video = ref.current;

    return () => {
      video?.pause();
    };
  }, []);

  return <video ref={ref} src={src} controls />;
}

When Activity becomes hidden, React cleans up Effects, but the DOM node can remain. Some native elements such as video, audio, and iframe can therefore have behavior that is different from true DOM removal.

Question 98AdvancedComparison

What are the 'use memo' and 'use no memo' directives in React Compiler?

Direct answer

'use memo' explicitly opts a function into compiler optimization in configurations where that matters, while 'use no memo' opts a function out and should usually be treated as a targeted escape hatch.

DirectivePurposeTypical use
"use memo"Request compiler optimization for the function/moduleAnnotation or incremental adoption strategies
"use no memo"Prevent compiler optimizationTemporary compatibility or debugging escape hatch
compiler-directives.jsx
function LegacyGrid() {
  "use no memo";

  return <ThirdPartyGrid />;
}

function OptimizedPanel() {
  "use memo";

  return <ExpensivePanel />;
}
Question 99AdvancedPractical

How would you determine whether a React re-render is actually a performance problem?

Direct answer

Measure before optimizing: use React DevTools Profiler or the Profiler component to identify expensive commits, compare actual rendering cost, and then optimize the specific component or data flow causing measurable latency.

App.jsx
function onRender(
  id,
  phase,
  actualDuration,
  baseDuration
) {
  console.log({
    id,
    phase,
    actualDuration,
    baseDuration
  });
}

function App() {
  return (
    <Profiler id="Results" onRender={onRender}>
      <Results />
    </Profiler>
  );
}
actualDuration
Time spent rendering the profiled subtree for the current update
baseDuration
Estimated cost of rendering the subtree without memoization benefits
phase
Whether the measured commit is a mount, update, or nested update
Question 100AdvancedConcept

What does flushSync do, and why is it considered a last-resort React API?

Direct answer

flushSync forces React to synchronously flush qualifying updates and update the DOM before returning, which is useful for rare browser or third-party integration requirements but can hurt performance and interfere with normal scheduling.

print.js
function handleBeforePrint() {
  flushSync(() => {
    setIsPrinting(true);
  });

  // By here, the DOM reflects isPrinting.
  window.print();
}
  • Useful when: an external browser or third-party API requires the DOM to reflect a React update synchronously before the next statement.
  • Performance cost: it bypasses normal scheduling advantages and may force other pending work to flush.
  • Suspense impact: a synchronous flush can cause pending Suspense fallbacks to appear.