Menu

React Interview Questions and Answers (React 19)

Around 30 React interview questions from beginner to advanced, each with a short answer an interviewer would accept and live code for the ones that are easier to see than to read.

This page includes runnable editors - edit, run, and see output instantly.

These are the React interview questions that come up most often, grouped by level and answered the way an interviewer expects: short, correct for React 19, and with the reason behind the rule. Where seeing the behaviour beats reading about it, the answer has a live editor, and a few questions ask you to predict the console output before you run it.

Before you click: what does the console under the preview print, and what does the button show? The answer is in the beginner section below.

Beginner questions

What is React?

React is a JavaScript library for building user interfaces from components. You write functions that return a description of the UI for the current data, and when that data changes React works out what changed and updates the DOM for you. It handles the view layer only: routing, data fetching and forms come from other libraries or from a framework such as Next.js.

What is JSX?

JSX is a syntax extension that lets you write markup inside JavaScript. A compiler (Babel, esbuild, SWC) turns each tag into a call that creates a React element, so <p className="note">{text}</p> becomes an object with type: 'p' and the props. Because it is JavaScript, you use className instead of class, put expressions in {}, and every tag must close. The JSX page covers the rules in detail.

What is the difference between a component and an element?

A component is a function (or class) that takes props and returns UI. An element is the plain object that JSX produces, describing what to render: <Avatar size={40} /> is an element whose type is the Avatar function. React calls your component to turn elements into more elements, all the way down to DOM tags. Elements are cheap and immutable; you never call a component yourself.

What is the difference between props and state?

Props are passed in by the parent and are read only inside the component. State is owned by the component, changes over time through a setter, and every change schedules a new render. A common way to say it: props configure a component, state is its memory. The same value can be state in a parent and a prop in its child.

What does the first example on this page log?

It logs logged: 0, and the button shows Count: 1, not 2. State is a snapshot: count is a constant for the whole render, so both setCount(count + 1) calls compute 0 + 1, and the log reads the old value because the new one only exists in the next render. To add two, use the updater form: setCount((c) => c + 1) twice.

Why do lists need keys, and why is the index a bad key?

React uses the key to match each list item with the one from the previous render. If you use the array index and insert an item at the top, every index shifts, so React keeps each row's state at its old position and attaches it to the wrong data.

Tick Ada, then click "Add to top": the tick jumps to the new first row. Change key={index} to key={person.id} and try again, and the tick stays with Ada. In development React also warns when keys are missing; the preview runs like a production build, so you will not see that warning here.

What is a controlled input?

An input whose value comes from React state: you pass value and update the state in onChange, so React is the single source of truth and you can validate or transform every keystroke. An uncontrolled input keeps its own value in the DOM and you read it when needed, through a ref or the form's FormData. Controlled inputs are the default choice when the UI reacts to what the user types.

What does lifting state up mean?

When two components need the same data, you move the state to their closest common parent and pass it down as props, along with a function to change it. The children stop owning their own copies, so they can never disagree. It is the standard answer to "how do sibling components share state" before reaching for context or a store.

What are the rules of hooks?

Call hooks only at the top level of a component or a custom hook, never inside conditions, loops or nested functions, and only from React functions, not from plain JavaScript functions. React identifies each hook by the order of the calls, so that order must be identical on every render. The eslint-plugin-react-hooks package enforces both rules.

What is a fragment?

A fragment groups several elements without adding a DOM node: <>...</>, or <Fragment key={id}> when you need a key inside a list. A component must return one root, and fragments let that root be several siblings, which matters inside tables and flex layouts where an extra div would break the markup.

Intermediate questions

How does the useEffect dependency array work?

React runs the effect after the render is committed (usually after the browser paints), then again after any later render in which a value in the array changed (compared with Object.is). With no array it runs after every render; with [] it runs once after the first render. Every value from the component that the effect reads belongs in the array, and the linter tells you when one is missing.

When does effect cleanup run?

The function you return from an effect runs before the effect runs again with new dependencies, and once when the component unmounts. That is where you undo what the effect set up: clear a timer, remove a listener, close a connection.

Click "Switch room" and watch the console: the cleanup for the old room runs first, then the effect connects to the new one. "Hide chat" runs only the cleanup. In development, StrictMode adds one extra connect, disconnect, connect on mount to check that your cleanup works; the preview runs like a production build, so you only see the real sequence.

Why does my state look stale inside setInterval?

The interval callback is a closure over the count from the render that created it. With an empty dependency array the effect never runs again, so the callback keeps reading that first count forever.

broken reaches 1 and stops, because every tick computes 0 + 1. fixed keeps counting, because the updater function receives the latest value. Adding broken to the dependency array also works, at the cost of clearing and recreating the interval every second.

What is batching?

React groups several state updates into a single render. Since React 18 this applies everywhere: event handlers, timeouts, promises and native event listeners. If you need the DOM updated immediately after one update, flushSync from react-dom opts out, but you rarely need it.

The click logs one render 1 1 1, not three renders. Three state updates inside a timeout used to mean three renders before React 18.

What does this log? (effect order)

Read the code and write down the four lines the console will print, in order, before you look at it.

Rendering goes top down: render App, then render Child. Effects run bottom up, after the whole tree is committed: effect Child, then effect App. A parent's effect can rely on its children's effects having already run.

What is the difference between useMemo and useCallback?

useMemo(() => compute(a, b), [a, b]) caches the result of a calculation. useCallback(fn, [deps]) caches the function itself, so it is the same as useMemo(() => fn, [deps]). Both only help when something downstream compares by reference: a memo child, or another hook's dependency array. Since React Compiler 1.0 (October 2025) a build step can add this memoization automatically, but manual memoization still works and you will still see it in most codebases.

What does React.memo do, and why does it often need useCallback?

memo(Component) skips re-rendering the component when its props are the same as last time, compared one by one with Object.is. A function written inline in the parent is a new function on every render, so it counts as a changed prop and defeats memo. useCallback keeps the same function between renders.

Clear the console and click "Re-render parent": only render inline handler appears. The other child got the same function and was skipped. Remove memo(...) around Button and both log on every click, which shows useCallback alone does nothing.

What is context, and what does it cost?

Context passes a value to every component below a provider without threading it through props: createContext, then <ThemeContext value={theme}> in React 19 (or <ThemeContext.Provider>), and useContext(ThemeContext) to read it. The cost is that every component that reads the context re-renders when the value changes, and memo does not stop it. Keep it cheap by splitting unrelated values into separate contexts, wrapping an object value in useMemo, and keeping fast-changing state out of app-wide context. See useContext.

What are refs, and when do you use one instead of state?

useRef(initial) returns an object whose current property persists across renders, and changing it does not trigger a render. Use a ref for values the screen does not depend on (a timer id, the previous value, a flag) and for DOM access (<input ref={inputRef}> then inputRef.current.focus()). If the value is shown on screen, it belongs in state.

What is the virtual DOM, and what is reconciliation?

On every render React builds a new tree of elements and compares it with the previous one; this comparison is reconciliation. If an element's type changed (a div became a section, or ProfileA became ProfileB), React destroys that subtree and its state and builds a new one. If the type is the same, it keeps the DOM node and updates the changed props, and it uses keys to match children in lists. "Virtual DOM" is the popular name for that in-memory tree; the speed comes from touching only what changed, not from the tree itself being fast.

What is a custom hook?

A function whose name starts with use and that calls other hooks, so you can reuse stateful logic between components: useOnlineStatus, useLocalStorage, useDebouncedValue. Each component that calls it gets its own independent state; a custom hook shares logic, not data. See custom hooks.

What does StrictMode do?

<StrictMode> turns on extra checks in development only. It renders components twice to expose impure rendering, runs effects setup, cleanup, setup once on mount to expose missing cleanup, does the same for ref callbacks, and warns about deprecated APIs. None of this happens in a production build, so a double console log in development is expected and not a bug.

Advanced questions

What does this log? (render, layout effect, effect)

One more prediction. Three logs, three different moments in a render.

The order is render, then useLayoutEffect, then useEffect, even though useEffect is written first. Layout effects run after React updates the DOM but before the browser paints, which is why they suit measuring an element; normal effects run later, usually after paint, and should be the default.

What is an error boundary?

A class component that catches errors thrown while rendering its children and shows a fallback instead of unmounting the whole app. It needs static getDerivedStateFromError (to switch to the fallback) and usually componentDidCatch (to log). There is still no hook equivalent, so in function-component codebases teams write one class or use the react-error-boundary package.

Click "Break it": the fallback replaces only the boundary's children, the button stays, and React still reports the caught error in the console. Boundaries do not catch errors in event handlers, in async code like setTimeout, or in the boundary itself. For those you use try/catch and set state.

What is a portal?

createPortal(children, domNode) from react-dom renders children into a different DOM node, typically document.body, while keeping them in the same place in the React tree. Modals, tooltips and toasts use it to escape a parent's overflow: hidden or stacking context. Context still works through a portal, and events bubble through the React tree, so a click inside the portal reaches the parent's onClick even though the DOM nodes are elsewhere. See portals.

What are Suspense and lazy?

lazy(() => import('./Chart')) loads a component's code the first time it renders, which splits your bundle. <Suspense fallback={<Spinner />}> shows the fallback while anything inside it is still loading: lazy code, or data read with use(promise) or a framework that supports Suspense. Placing boundaries decides which parts of the page wait together.

import { lazy, Suspense } from 'react';

const Chart = lazy(() => import('./Chart.jsx'));

export default function Dashboard() {
    return (
        <Suspense fallback={<p>Loading chart...</p>}>
            <Chart />
        </Suspense>
    );
}

What does useTransition do?

It marks a state update as non-urgent. const [isPending, startTransition] = useTransition() and startTransition(() => setTab('posts')) let React keep the current screen responsive and interrupt the slow render if a more urgent update arrives, like a keystroke. isPending tells you to show a hint. In React 19 the function you pass can be async, which is what React calls an action. Do not use it to update a text input's own value; that update must be urgent.

What are React Server Components?

Components that run only on the server (or at build time) and send their rendered result to the browser, never their code. They can be async and read a database or the file system directly, but they cannot use state, effects or browser APIs. A file marked 'use client' starts a client boundary where interactive components live, and 'use server' marks server functions that client code can call. You use them through a framework such as Next.js with the App Router; plain Vite apps do not have a server to run them.

What changed in React 19?

  • Actions: async functions in transitions, with pending state handled for you. A <form action={fn}> calls fn with the form's FormData.
  • New hooks: useActionState for a form's result and pending state, useOptimistic for optimistic UI, and useFormStatus in react-dom.
  • use: reads a promise (suspending until it resolves) or a context, and unlike other hooks it can be called inside a condition.
  • ref as a prop: function components receive ref like any other prop, so forwardRef is no longer needed for new code. Ref callbacks can return a cleanup function.
  • <Context> as a provider, plus <title> and <meta> tags that hoist into the document head.
  • Removals: ReactDOM.render, string refs, legacy context, and defaultProps on function components (use default parameters).
// React 19: ref is a normal prop
function TextInput({ ref, ...props }) {
    return <input ref={ref} {...props} />;
}

The React 19 page has runnable examples of each.

How do you test React components?

With React Testing Library and a runner such as Vitest or Jest. You render the component, find elements the way a user would (by role, label or text), interact with user-event, and assert on what is visible, not on internal state. That keeps tests valid through refactors.

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';

test('counts clicks', async () => {
    const user = userEvent.setup();
    render(<Counter />);
    await user.click(screen.getByRole('button', { name: /clicked 0 times/i }));
    expect(screen.getByRole('button')).toHaveTextContent('Clicked 1 times');
});

toHaveTextContent comes from @testing-library/jest-dom. For whole flows across pages, teams add Playwright or Cypress on top.

How do you find and fix a performance problem?

Measure first. Open the Profiler tab in React DevTools, record the slow interaction, and read the flame chart: it shows which components rendered, how long each took, and (with the "record why each component rendered" setting) why. Typical fixes, in the order to try them: move state down so fewer components depend on it, pass slow subtrees as children, memoize the expensive part with memo, useMemo and useCallback, virtualize long lists, and defer heavy updates with useTransition or useDeferredValue. Profile in a production or profiling build; development builds are slower and exaggerate render times.

Why should a component be pure?

Given the same props, state and context, a component should return the same JSX and change nothing outside itself while rendering. React may render a component more than once, out of order, or throw a render away (transitions, Suspense, StrictMode), so side effects in the body such as mutating a variable or sending a request run an unpredictable number of times. Side effects belong in event handlers first, and in effects when no event caused them.

When should you not use an effect?

When the value can be computed during render (filtered lists, full names, totals), when the work is caused by a user action (put it in the event handler), and when you want to reset state on a prop change (use a key). Effects are for synchronizing with something outside React: a network connection, a browser API, a third-party widget. Chains of effects that set state are a common source of extra renders and bugs.

Frequently Asked Questions

What is React?

React is a JavaScript library for building user interfaces out of components. You describe what the screen should look like for the current data, and React updates the real DOM when that data changes.

What is the difference between state and props?

Props are inputs a parent passes to a component, and the component treats them as read only. State is data a component owns and changes over time with a setter, which makes React render it again.

What are hooks in React?

Hooks are functions whose names start with use that let a function component use React features: useState for state, useEffect for side effects, useContext for context, useRef for values that do not trigger renders, and more.

What is the virtual DOM?

It is the name for React's in-memory description of the UI. On each render React builds a new description, compares it with the previous one, and applies only the differences to the real DOM. That comparison is called reconciliation.

Why do keys matter in React lists?

A key tells React which item in a list is which between renders. With stable keys (like an id) React keeps each item's state and DOM node attached to the right data when items are added, removed or reordered. Using the array index breaks this when the order changes.

What is JSX?

JSX is a syntax extension that lets you write HTML-like markup in JavaScript. A compiler turns each tag into a function call that creates a React element, so <h1>Hi</h1> becomes a plain object describing an h1.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED