React
React is the default frontend framework in interviews, so you are expected to explain it end to end. That means how components and JSX become elements, how hooks hold state and effects, how reconciliation decides what re-renders, and how the newer server/Suspense model splits work between server and client.
on this pageshowhide
guide
overview
~1 minReact is a library for describing a user interface as a function of state: you write components that return a description of the screen, and React works out which DOM changes turn the last description into the next one. Interviewers lean on it because so much frontend work runs through it, and because the gap between using React and understanding it shows quickly. Someone who can say *why* a component rendered, *when* an effect ran and *where* a piece of state should live debugs faster than someone who memorised the API. The hub follows that order of questions. [Components and JSX](/topics/fe-react-components-jsx) is the authoring surface: what JSX becomes, how props and children flow down, how events and forms are wired. [Built-in hooks](/topics/fe-react-hooks) covers the contract of each hook, and [state and context](/topics/fe-react-state-context) turns those hooks into architecture: where state lives, how it is shaped, how it is shared. [Effects and lifecycle](/topics/fe-react-effects-lifecycle) is how a component reaches outside itself, and where most real bugs sit. [Rendering and reconciliation](/topics/fe-react-reconciliation) explains the engine underneath — what schedules a render, how the tree is compared, what gets committed — and [performance and memoization](/topics/fe-react-performance) builds on it. [Server Components and Suspense](/topics/fe-react-server-suspense) is the newer model, where part of the tree never reaches the browser. Junior rounds check the model: props against state, the dependency array, keys in a list, controlled inputs. Middle rounds bring stale closures, effect cleanup and re-render causes. Senior and principal rounds turn into design conversations — where state belongs, when memoization pays, what belongs on the server — and expect reasons rather than reflexes. Learn components and the core hooks first, then the render-and-commit cycle, because effects, performance and the server model all assume it.
primer
### UI is a function of state A component is a function from props and state to a description of UI. It does not change the screen; it returns elements, plain objects, and React decides what to write to the DOM. Rendering should therefore be pure: same inputs, same output, no side effects in the body. Most rules that feel arbitrary — no mutation, no setState during render, effects kept separate — follow from that single constraint. ### Each render is a snapshot Every render sees its own props and state as constants. A setter does not change the variable you are holding; it asks React for a future render with a new value. Handlers, effects and timers close over the render that created them. Stale values, updates that seem lost and intervals that stop counting are all the same idea met from different sides, and interviewers use them to test whether you hold the model or only the syntax. ### Hooks are identified by call order React keeps a component's hook state in slots and finds each one by position, not by name. That is where the rules of hooks come from — top level only, same order on every render — and why custom hooks compose freely: a custom hook is just more calls in the same sequence. Break the order and one hook quietly reads another's data. ### Render, then commit, then effects Work happens in phases. **Render** calls your components and compares the result with the previous tree; it can run more than once, be paused or be thrown away. **Commit** applies the changes to the DOM in one pass. Effects run after commit, layout effects before the browser paints and passive effects, usually, after it. Knowing which phase a line of code belongs to answers most timing questions. ### Identity decides what survives React keeps state attached to a position in the tree, qualified by element type and `key`. The same type at the same position updates in place; a different type or key starts over, state and DOM included. That makes keys a tool for resetting state deliberately, and not only a way to silence a warning on lists. ### Effects synchronise with the outside world An effect keeps something outside React — a subscription, a socket, a timer, a DOM API — in step with the current render, and its cleanup undoes the previous setup. An effect that only copies one piece of state into another is usually a mistake: derive the value during render instead. Senior rounds probe whether you can tell an effect that synchronises from one that patches the data flow. ### Re-renders are cheap until they are not A component renders again when its state changes, a context it reads changes, or its parent renders. That is by design, and most renders cost little. Memoization trades memory and comparison work for skipped renders, and only helps when references stay stable. The strong answer measures first and often fixes the cost by moving state or restructuring the tree rather than by wrapping components. ### The tree spans two runtimes With Server Components, part of the tree runs only on the server and sends its output, not its code; client modules ship to the browser and hold the interactivity. Suspense boundaries mark where the UI may wait and stream in later. Questions here are about placement: what runs where, what may cross the boundary, and what that does to bundle size and first paint.
- Element
- An immutable plain object describing what to render: a type, props and an optional key. Components return elements; React turns them into DOM.
- JSX
- Syntax that compiles to function calls creating elements. It is not HTML: attributes are props, and expressions go in braces.
- Hook
- A function whose name starts with use and which reads or registers React-managed state or behaviour. Called only at the top level of components and other hooks.
- Dependency array
- The list of values that decides whether an effect or memoized value is recomputed. React compares each entry with the previous render's using Object.is.
- Effect cleanup
- The function an effect returns. React calls it before the effect runs again and when the component unmounts, to undo the previous setup.
- Controlled input
- A form field whose value comes from React state and changes only through a handler, as opposed to one whose value lives in the DOM.
- Context
- A way to pass a value to any descendant without threading props. It carries a value; the state behind it still lives somewhere else.
- Fiber
- React's internal unit of work: one node per component or host element, holding its state, props and links to parent, child and sibling.
- Reconciliation
- Comparing the new element tree with the previous one to decide which fibers to keep, update, create or delete.
- Key
- A prop that gives an element an identity among its siblings, so React can match it across renders independently of its position.
- Batching
- Grouping several state updates into one render. Since React 18, with createRoot, this happens automatically, including inside promises and timeouts.
- Transition
- An update marked non-urgent, which React may interrupt or abandon so urgent input such as typing stays responsive.
- Suspense boundary
- A component that shows a fallback while something inside it is not ready, such as lazy code or data, then reveals the content.
- Hydration
- Attaching React to HTML already rendered on the server: the client renders the same tree and adopts the existing DOM instead of recreating it.
- Server Component
- A component that runs only on the server. Its output is sent to the client, its code is not, and it cannot hold state or handle events.
- 'use client'
- A directive at the top of a module that marks where the client bundle begins. That module and everything it imports ship to the browser.
- Error boundary
- A component that catches errors thrown while rendering its subtree and shows fallback UI in its place. Still written as a class.
Follow one interaction through the system. A click runs a handler, which calls a setter; React queues the update and, once the handler finishes, renders the component that owns that state and everything beneath it. Each component returns elements, and reconciliation walks the new elements against the existing fiber tree, matching them by type and key and bailing out where it can prove nothing changed. The commit applies the difference to the DOM, attaches refs, runs layout effects, and then, usually after the browser has painted, runs passive effects — cleanups of the previous render first. Every other section of this hub is a view of one step on that path: - **Components, JSX and hooks** are what you write at the start of it; the hooks' contracts decide what each render sees. - **State and context** decide *which* component owns the update, and therefore how much of the tree renders again. - **Effects** live at the end of the path, and their dependency arrays decide whether they run at all. - **Reconciliation** is the middle; batching, update queues and concurrent rendering change when and how often it runs. - **Performance** work removes steps from the path: fewer components rendered, less work per render, less code loaded before first paint. The server model extends the same tree across a network boundary. Server Components render first, on the server, and their output travels to the browser alongside the client components they reference; Suspense marks the places that may stream in later; hydration then attaches the client runtime to HTML that already exists. A single page file shows several of these ideas meeting: ```jsx // page.jsx: a Server Component; its code never reaches the browser export default async function Page({ id }) { const user = await loadUser(id); // data read on the server return ( <> {/* ProfileForm lives in a 'use client' module; its props are serialized */} <ProfileForm key={user.id} user={user} /> <Suspense fallback={<OrdersSkeleton />}> <Orders userId={user.id} /> {/* async child, streamed in later */} </Suspense> </> ); } ``` The `key` gives the client form fresh state per user, the prop crossing into the client module must be plain data, and the boundary lets the page show the profile before the orders are ready.
- Components and JSX →
What JSX compiles to, and how props, children and events move through a tree; the vocabulary every other section uses.
- Built-in Hooks →
The contract of each built-in hook, including call order and dependency arrays, which most later bugs trace back to.
- State and Context →
Where state should live and how it is shared, which decides how much of the tree renders on each update.
- Rendering and Reconciliation →
The render and commit cycle, keys and batching: the engine that makes timing and re-render questions answerable.
- Effects and Lifecycle →
Effects, cleanup, refs and StrictMode, easier once you know when the commit happens and what each render captures.
- Performance and Memoization →
Memoization, profiling and splitting build on reconciliation; learn it after, so each technique has a clear cost.
Saying a component re-renders because its props changed: props change because the parent rendered, and state or a context it reads are the other triggers.
Reading state right after calling its setter and expecting the new value; the setter schedules a future render, and the current one keeps its snapshot.
Using useEffect to keep one piece of state in sync with another, when the value could be computed during render with no extra pass.
Leaving a value out of the dependency array to stop an effect re-running, instead of changing what the effect reads — the usual source of stale closures.
Using the array index as a
keyfor lists that reorder, insert or delete; state and DOM stay with the position, not the item.Wrapping everything in
React.memo,useMemoanduseCallbackby reflex, without measuring, and without noticing that one unstable prop makes the comparison fail every time.Treating Context as a state manager: it only delivers a value, and every consumer renders again when that value's identity changes.
Calling the double effect run in development a bug to be suppressed; StrictMode is exposing an effect whose cleanup does not undo its setup.
Adding
'use client'to the top of the tree to make an error go away, which moves everything it imports into the browser bundle.
This guide assumes React 19, where Server Components, Actions and the `use` API are stable. Interviewers still ask about the releases that shaped today's model, because many codebases sit on older versions: - **16** replaced the reconciler with **Fiber**, which made rendering interruptible and introduced error boundaries. - **16.8** added **hooks**; function components could hold state and effects, and class lifecycles stopped being the default way to write React. - **17** attached event listeners to the root container instead of the document and introduced the new JSX transform, so files no longer needed to import React for JSX. - **18** introduced `createRoot` and concurrent features: automatic batching outside event handlers, transitions, `useDeferredValue`, `useId`, `useSyncExternalStore`, and streaming server rendering with Suspense. StrictMode began mounting components twice in development to surface effects without cleanup. - **19** added Actions and the form hooks `useActionState`, `useFormStatus` and `useOptimistic`, the `use` API, `ref` as an ordinary prop for function components, and rendering a context directly as its provider. It also removed long-deprecated APIs, such as `ReactDOM.render` and string refs. The React Compiler is a separate build-time tool that inserts memoization automatically, which changes how much hand-written `useMemo` and `useCallback` a codebase needs. When an answer depends on batching, effect double-runs or how refs reach a function component, name the version you are describing.
React is a rendering library, not a full application framework, so interviewers expect you to name what sits around it. Routing, data loading and server rendering usually come from a framework: Next.js and React Router are the common choices, and Server Components need a framework or bundler integration to work at all. Server data is typically handled by a query library such as TanStack Query, which caches, deduplicates and revalidates requests, rather than by effects written by hand. Shared client state goes to `useReducer` with context, or to an external store such as Redux Toolkit or Zustand when many components subscribe to parts of a large state. Forms, tests and styling have their own common picks, with React Testing Library the usual answer for component tests. Among UI frameworks, React competes most directly with Vue, Angular, Svelte and Solid. The trade-off an interviewer expects you to state is the rendering model: React re-runs components and compares their output, while frameworks built on fine-grained reactivity, such as Solid and Svelte, track which values each piece of UI reads and update only those parts. React's answer to that cost is memoization, now increasingly automated by its compiler; the others' answer is finer-grained reactivity with a different authoring model. React Native carries the same component and hook model to mobile platforms.
explore
- Components and JSX64 questions
- Component Anatomy and Typing5 questions
- JSX Syntax and Semantics15 questions
- Props and Composition17 questions
- Event Handling14 questions
- Forms and Inputs9 questions
- Portals4 questions
- Built-in Hooks52 questions
- Rules of Hooks and the Lint Plugin5 questions
- useState5 questions
- useReducer5 questions
- useEffect and useLayoutEffect5 questions
- useRef and useImperativeHandle5 questions
- useContext4 questions
- useMemo and useCallback4 questions
- useTransition and useDeferredValue5 questions
- useSyncExternalStore and useId5 questions
- use() and Reading Resources4 questions
- Form and Action Hooks5 questions
- State and Context49 questions
- State Modeling12 questions
- Reducers and Complex State9 questions
- Context API13 questions
- Custom Hooks10 questions
- Server State vs Client State5 questions
- Effects and Lifecycle62 questions
- The Effect Model16 questions
- Data Fetching in Effects13 questions
- Refs and DOM Interaction16 questions
- StrictMode and Development-Only Behaviors5 questions
- Error Boundaries6 questions
- Class Lifecycle and Hook Equivalents6 questions
- Rendering and Reconciliation49 questions
- The Render Phase4 questions
- The Commit Phase and Effect Order4 questions
- Fiber Tree and Virtual DOM4 questions
- The Work Loop and Interruptibility5 questions
- Element Diffing and Bailouts5 questions
- Keys and List Reconciliation5 questions
- State Updates as a Queue4 questions
- Automatic Batching and flushSync4 questions
- Concurrent Rendering14 questions
- Performance and Memoization41 questions
- Memoization Tradeoffs5 questions
- Referential Equality Traps4 questions
- Unnecessary Re-Render Causes4 questions
- React DevTools Profiler6 questions
- Profiler API4 questions
- Code Splitting with lazy and Suspense4 questions
- List Virtualization5 questions
- React Compiler5 questions
- Composition over Memoization4 questions
- Server Components and Suspense47 questions
- React Server Components14 questions
- SSR and Hydration15 questions
- Suspense Boundaries13 questions
- Actions and Form Primitives5 questions
questions
364 · 7 sectionsIn React 19, what exactly is a function component, how does it differ from a class component, and is there anything a class can still do that a function cannot?
basics
~20 sA function component is a plain function that takes a props object and returns React elements, using hooks for state and effects. A class extends React.Component and implements render() plus lifecycle methods. Only error boundaries still require a class.
In React, an inline handler such as onClick={() => setOpen(true)} is a brand-new function on every render. Why does that happen, and when is it actually a problem?
basics
~20 sEvery render re-runs the component body, so the arrow expression evaluates again into a new function object. The allocation itself is cheap; the new identity only matters where something compares it, such as a memoized child or a dependency array.
In React JSX, what is the difference between writing onClick={handleClick} and onClick={handleClick()}, and what actually happens with the second form?
basics
~20 sThe first passes the function so React can call it on click. The second calls it during render and passes its return value, usually undefined, so nothing happens on click and the side effect fires on every render.
In a React onSubmit or onClick handler, why does `return false` not stop the browser's default behaviour, and what do you write instead?
basics
~10 sReact ignores a handler's return value entirely. Returning false only cancels defaults in inline HTML attributes and jQuery handlers. In React you call e.preventDefault(), and e.stopPropagation() separately if you also want to stop bubbling.
In React 19, what object does React pass to an event handler such as onClick, and how do you reach the underlying browser event from it?
basics
~10 sReact passes a SyntheticEvent: a cross-browser wrapper that mirrors the DOM event interface (type, target, preventDefault, stopPropagation). The untouched browser event is always available on e.nativeEvent for anything React does not normalize.
In React, from which functions may you call a hook such as useState, and which common call sites are forbidden?
basics
~20 sHooks may be called only from the top level of a React function component body or from another hook (a function whose name starts with "use"). Event handlers, plain helper functions, class components, and nested callbacks are all forbidden.
In React, what does the argument passed to createContext(defaultValue) actually do, and what does useContext(MyContext) return when no matching provider is mounted above the component?
basics
~20 screateContext's argument is a fallback used only when no matching provider sits above the consuming component. useContext then returns it silently instead of throwing. It is not an initial value, and a mounted provider never falls back to it.
In React, what is the difference between calling useEffect(fn) with no second argument, useEffect(fn, []) with an empty array, and useEffect(fn, [a, b])?
basics
~20 sThe second argument controls re-runs: omitting it runs the effect after every render, an empty array runs it once after mount, and a populated array re-runs it only when one of the listed values changes.
In React, what is the difference between useMemo(factory, deps) and useCallback(fn, deps), and how are the two related?
basics
~10 suseMemo calls the factory you pass and caches its return value; useCallback caches the function itself without ever calling it. They are one mechanism: useCallback(fn, deps) behaves exactly like useMemo(() => fn, deps).
In React, what arguments does useReducer take and what does it return, and what happens when you call the dispatch function it gives you?
basics
~20 suseReducer takes a reducer function, an initial value, and an optional init function. It returns the current state and a dispatch function; calling dispatch with an action schedules an update whose next state React computes by running the reducer.
When a React context provider is rendered with a new value, which components re-render because of that context change — every descendant of the provider, or only the ones that read the context?
basics
~20 sOnly components that read that context re-render because of the change. React notifies the consumers it finds below the provider. Other descendants re-render for a different reason: their own parent re-rendered and re-created their elements.
Is React Context a state-management library? Explain what Context actually provides, and what it does not provide compared with an external store such as Redux or Zustand.
basics
~20 sReact Context is a dependency-injection channel, not a state manager: it carries one value down the tree so descendants can read it without prop drilling. It stores nothing itself — the state still lives in useState, useReducer, or an external store.
In React, when should logic inside a component be extracted into a custom hook, and when is a plain JavaScript function the better choice instead?
basics
~20 sExtract a custom hook when the logic calls other hooks, or when the same hook wiring repeats across components. If the logic is a pure computation over its arguments, keep it a plain function outside the component.
In React, two sibling components need the same value — one displays it and the other edits it. Where does that state go, and what does each sibling receive instead?
basics
~20 sMove the state into the siblings' nearest common ancestor. That parent owns it with useState and passes the current value down to both children, plus a callback that lets the editing child ask for a change.
A React component holds `firstName` and `lastName` in useState and keeps a third `fullName` state in sync with a useEffect that calls setFullName(firstName + ' ' + lastName). What is wrong with this, and what would you write instead?
basics
~20 sfullName is derivable, so storing it duplicates state. The effect runs after React commits, so the screen briefly shows a stale name and every keystroke costs a second render pass. Compute it during render as a plain const.
In React, a component polls by calling setInterval inside a useEffect. What must that effect return, and what goes wrong on a screen the user opens and leaves repeatedly?
basics
~20 sThe effect must return a cleanup function that calls clearInterval with the id setInterval returned. Without it, every mount leaves another live timer behind, so abandoned components keep polling forever and traffic multiplies with each visit.
A React component loads its data by calling `fetch` inside `useEffect` and storing the result with `useState`. Why does that component always render at least once with no data, and what does that force you to write by hand?
basics
~10 sEffects run after React has rendered and committed the component, so the first render happens before the request is even sent. Every fetch-in-effect component therefore needs hand-written loading, error and empty states.
In React, what is the difference between calling useEffect(fn) with no second argument, useEffect(fn, []), and useEffect(fn, [a, b])?
basics
~20 sOmitting the second argument runs the effect after every render. An empty array runs it once after mount, with cleanup at unmount. A list of values re-runs it whenever any listed value changes, compared with Object.is.
In a React component, a Buy button must POST an order and then show a confirmation toast. One version does both inside the onClick handler; another sets `ordered` state in the handler and runs `useEffect(() => { if (ordered) { postOrder(); showToast(); } }, [ordered])`. Which is correct, and why?
basics
~20 sBoth belong in the onClick handler: they are caused by a specific user action, not by the component being displayed. Routing them through state and an effect adds a render pass, an extra state field, and a path for the request to fire twice.
In a React component you subscribe to a media query with window.matchMedia('(max-width: 600px)') inside useEffect. What must that effect return, and what goes wrong in an app that mounts and unmounts that component many times if it doesn't?
basics
~20 sThe effect must return a cleanup function that removes the exact listener it added. Without it, every mount leaves another live listener on the MediaQueryList, so subscriptions pile up, unmounted components keep reacting, and the retained closures leak memory.
In a React 19 component, one click handler calls setCount, setName and setOpen one after another, yet the component body logs only one render. What is automatic batching, and why does React work this way?
basics
~20 sAutomatic batching means React collects every state update queued while the current work runs and applies them in a single re-render instead of rendering once per setter. It avoids wasted renders and half-updated intermediate UI.
In a React function component that renders <input ref={inputRef} />, reading inputRef.current in the component body gives null, but reading it inside an effect gives the DOM element. What happens in between?
basics
~20 sRendering only computes what the UI should be, so no DOM node exists yet and the ref is still null. React then commits that output: it creates the DOM nodes, attaches refs to them, and only afterwards runs your effects.
In a React 19 search box, the onChange handler calls setQuery(value) directly but wraps setFilterTerm(value) in startTransition. Why must the input's own state update stay outside the transition?
basics
~20 sThe typed value is urgent: React must commit it right away or the characters the user typed appear late. An update marked with startTransition is non-urgent and interruptible, so putting the input's own value in one makes the field feel stuck.
In React, the element at one position in the tree is a <div> on one render and a <section> on the next, with identical children inside. What does React do with that node and everything beneath it?
basics
~20 sReact tears down the old subtree and builds a new one: DOM nodes are recreated, component state is lost, effect cleanups run and refs detach. Types must match at a position for React to update in place.
React is usually described as using a "virtual DOM". Concretely, what is that virtual DOM made of, and is updating it faster than updating the real DOM directly?
basics
~20 sReact's virtual DOM is a tree of plain JavaScript objects describing the intended UI. They are cheap to create, so React can compare them and write only the DOM that changed — not faster than optimal manual DOM work, just easier.
In React 19, how does React.lazy let a route component ship in its own chunk — what must the imported module expose, and what must be present in the tree when the lazy component first renders?
basics
~20 sReact.lazy(() => import('./Page')) returns a component whose code loads on first render. The imported module must expose that component as its default export, and the lazy element must render inside a Suspense boundary that supplies a fallback.
In React, a component is wrapped in React.memo. Which re-renders does that actually skip, and which does it not prevent?
basics
~20 sReact.memo skips a re-render caused by the parent, and only when every new prop is the same as the old one by a shallow comparison. Its own state updates, a context change it reads, or any changed prop still re-render it.
Both React.memo and useMemo are described as memoization in React, and candidates often use the names interchangeably. What does each one actually cache, and when would you reach for one rather than the other?
basics
~20 sReact.memo caches a component's rendered output and skips re-running it when its props are unchanged. useMemo caches one value inside a component that still re-renders. One avoids a render; the other avoids a computation during a render.
What does the React Compiler (babel-plugin-react-compiler) do to your components at build time, and which hand-written memoization does it make redundant?
basics
~20 sThe React Compiler is a build-time Babel plugin that rewrites components to cache their derived values and their JSX in per-instance slots, reusing them when inputs are unchanged. It replaces most hand-written useMemo, useCallback and React.memo.
In a React component, `const query = { term, page };` is built in the component body and used as `useEffect(() => { fetchResults(query).then(setRows); }, [query]);`. The effect fires after every render and never settles. Explain the mechanism and give two fixes.
basics
~20 sRebuilding query in the component body creates a new object on every render, and React compares each dependency with Object.is, so the effect re-runs, sets state, renders again, and loops. Depend on the primitive fields instead.
In React 19 you can pass a function to a <form> element's action prop instead of writing an onSubmit handler. What does React take over on your behalf when you do that?
basics
~20 sReact calls the function with the form's FormData, prevents the default navigation itself, and runs the call as an Action inside a transition — so React tracks pending state, surfaces errors, and resets an uncontrolled form after it succeeds.
In React, what does the fallback prop of <Suspense> render, and what decides when the user sees the fallback instead of the boundary's children?
basics
~20 sThe fallback prop holds the UI React shows in place of a <Suspense> boundary's children while something inside those children is not ready yet. React swaps the real children back in as soon as nothing inside that boundary is suspended.
In React 19, props passed from a Server Component to a Client Component are serialized into the RSC payload before they reach the browser. Which kinds of values survive that trip, and which ones make React throw?
basics
~20 sPrimitives, plain objects, arrays, Date, Map, Set, typed arrays, JSX elements, promises and Server Functions can cross. Ordinary functions, class instances and locally created symbols throw, because React must write every prop into a wire payload the browser reads back.
In a React 19 app that uses React Server Components, what is the fundamental difference between a Server Component and a Client Component?
basics
~20 sServer Components execute only on the server, once per request, and their code never ships to the browser. Client Components are sent to the browser as JavaScript, where they mount, hold state, and respond to user input.
In a React Server Components app, a file that starts with 'use client' imports a Button from another file that has no directive. Is that Button a client component, does its own file need a 'use client' line, and where in a file must the directive be written?
basics
~20 sYes, the Button is a client component. Files below a client boundary inherit it through imports and need no directive of their own. The directive must be the first statement of a file, above every import.