Top 30 Intermediate React & Next.js Interview Questions and Answers
30 intermediate multiple-choice React & Next.js interview questions, past the definitions: how the pieces fit together, what breaks in practice, and the trade-off behind a choice. They come from 30 bites in the React & Next.js library, the middle slice of the 144 React & Next.js interview questions in the library. Answer them here or read straight down. Every question carries the correct option, why it is correct, and a link to the bite it came from.
React, Next.js, Remix, RSC, React ecosystem
30 questions. Pick an answer, or open “Show the answer” to read it.
Answers are graded in your browser. Nothing is saved, and no XP or streak is earned here. The app keeps score.
Question 1 of 30
When a dynamic list reorders and items have local state, what happens if array indices are used as React keys?
Show the answer
Answer: d · React reuses component instances by position, causing state from one data item to appear on another.
Array indices tie identity to position, so React reuses the wrong component instance after reorder or deletion and state ends up attached to the wrong data item. Option B is wrong because React does not reset state when keys are unstable—it incorrectly preserves it on the reused instance.
Read the full bite: What is the purpose of React's key prop and index key risks?
Question 2 of 30
In React, when is an early return with if/else preferable to an inline ternary inside JSX?
Show the answer
Answer: a · When branches are large, structurally different, or to reduce nesting
Early returns improve readability when branches are large, structurally different, or deeply nested. Option B actually describes when an inline ternary is the better choice, not an early return.
Read the full bite: Describe two patterns for conditional rendering in JSX
Question 3 of 30
Why would wrapping two table cells in a Fragment be preferable to wrapping them in a div?
Show the answer
Answer: a · Fragments avoid creating an invalid HTML structure since they do not add an extra DOM node.
A div placed directly inside a table row creates invalid HTML, while a Fragment groups children without introducing any DOM node. Claiming a performance benefit is a common misconception; the primary reason to use Fragments is structural and semantic correctness, not optimization.
Read the full bite: What is a React Fragment and why use it over a div?
Question 4 of 30
A team passes a user object through Layout, Header, Navigation, and finally to UserMenu. What is the strongest argument for replacing this with Context or composition?
Show the answer
Answer: a · Layout, Header, and Navigation are coupled to a prop they ignore, making refactors and reuse harder.
Prop drilling is primarily a maintenance and coupling problem: intermediaries must accept and forward props they do not use, so renaming the prop or reusing those components elsewhere becomes painful. Option B is tempting but wrong because the card explicitly warns against confusing drilling with runtime performance issues like excessive re-renders.
Read the full bite: Explain prop drilling and why it's a problem
Question 5 of 30
You need to increment a React state variable three times within a single event handler. Which approach produces the correct final value?
Show the answer
Answer: c · Call setCount(prev => prev + 1) three times sequentially
Option C uses the functional updater so React queues each increment against the latest pending state. Option B fails because all three calls read the same closed-over value from the render snapshot, so each computes 0 + 1.
Read the full bite: What will count be after three setCount calls in a row?
Question 6 of 30
Which approach correctly fetches data inside useEffect while preventing memory leaks when the component unmounts?
Show the answer
Answer: a · Create an async function inside the effect, invoke it, and return a cleanup function that aborts the request.
Creating an async function inside the effect allows the outer callback to remain synchronous and return an abort cleanup function. Declaring the useEffect callback itself as async is a common mistake because it returns a Promise, breaking React's cleanup contract.
Read the full bite: How do you fetch data with useEffect and prevent memory leaks?
Question 7 of 30
A useEffect subscribes to an external store. When a dependency changes and the effect must re-run, when does the cleanup function execute?
Show the answer
Answer: d · Immediately before the effect re-runs with the new dependency values
React runs the cleanup function immediately before re-executing an effect when dependencies change, tearing down the previous render's side effects to prevent memory leaks and stale subscriptions. The most tempting distractor assumes cleanup is only for unmount, but that ignores the re-run scenario and fails under React 18 Strict Mode, which intentionally double-invokes effects to expose missing teardown logic.
Read the full bite: What is the purpose of the useEffect cleanup function?
Question 8 of 30
What is the key difference between useState(expensive()) and useState(() => expensive()) during re-renders?
Show the answer
Answer: a · The direct call executes on every render but React discards its result after mount, while the function runs only once during initialization.
JavaScript evaluates the direct argument before React can intercept it, so expensive() wastes cycles on every render even though React throws away the result after mount; the initializer function runs only once. Option D is tempting but wrong because lazy initialization does not prevent re-renders, it only avoids repeating expensive setup work inside them.
Read the full bite: Why pass a function to useState for expensive initial values?
Question 9 of 30
For which situation should you reach for useReducer instead of multiple useState hooks?
Show the answer
Answer: d · Coordinating several related fields that must update atomically from one action
useReducer excels when one action must update multiple interdependent fields atomically, centralizing transition logic outside the component. Option A is a common misconception because the hook itself does not memoize child renders or improve performance without additional optimizations like React.memo.
Read the full bite: Explain useReducer and when to prefer it over useState
Question 10 of 30
A ThemeContext.Provider wraps the entire app and passes an unmemoized object containing theme and toggleTheme. What is the main performance risk?
Show the answer
Answer: d · Every consumer re-renders whenever the Provider re-renders because the object reference changes each time
React compares context values by reference, so a new object literal on every render triggers re-renders in all consumers even if the theme data is unchanged. Option A is tempting because developers often assume context supports selective subscriptions by property, but React does not optimize that way.
Read the full bite: Use useContext to provide theme state without prop drilling
Question 11 of 30
A parent computes an expensive object and defines an inline handler passed to a React.memo child. Which hook combination correctly optimizes the computation and prevents unnecessary child re-renders?
Show the answer
Answer: d · useMemo for the object and useCallback for the handler
useMemo caches the computed object value, while useCallback preserves the function reference so React.memo's Object.is check sees an unchanged prop and skips the child render. Choosing useMemo for the handler confuses the two hooks because useMemo caches the returned value rather than the function reference, and omitting a hook creates a new inline function on every parent render.
Read the full bite: Explain the difference between useMemo and useCallback
Question 12 of 30
What fundamental difference distinguishes a custom hook from a HOC when reusing stateful logic in React?
Show the answer
Answer: b · A custom hook extracts logic into a plain function without adding nodes to the component tree.
Custom hooks reuse stateful logic as plain functions without adding nodes to the React tree or hiding prop sources, whereas HOCs wrap components and can create wrapper hell. Option D is tempting because it echoes the common misconception that hooks are just syntactic sugar for HOCs, but they represent a fundamentally different composition mechanism.
Read the full bite: Compare HOCs and custom hooks for sharing logic
Question 13 of 30
Which approach best demonstrates the idiomatic way to handle a variant prop in a styled-components Button?
Show the answer
Answer: c · Pass variant to a single styled.button and use an interpolated function inside the template literal to map the prop value to CSS rules
The card describes the idiomatic pattern as using a single styled.button with an interpolated function that reads props.variant to map CSS rules, keeping the API prop-driven and the component reusable. Splitting into separate components, using inline styles, or manually concatenating classNames are all explicitly identified as red flags that defeat the purpose of the CSS-in-JS library.
Read the full bite: How would you create a styled Button accepting a variant prop
Question 14 of 30
In this architecture, what is the primary responsibility of the custom React Context provider?
Show the answer
Answer: c · To hold the current mode string and toggle function while the CSS-in-JS ThemeProvider injects derived tokens into styles
The custom Context manages state and actions such as the mode string and toggle, while the CSS-in-JS ThemeProvider is what actually injects the derived theme tokens into component styles. Option B describes the library provider's job, and option D combines prop drilling with unnecessary rebuilds, both listed as common anti-patterns.
Read the full bite: Implement a light/dark theming system with CSS-in-JS and React Context
Question 15 of 30
How should a ProtectedRoute wrapper preserve the original destination when redirecting an unauthenticated user from /dashboard to login?
Show the answer
Answer: d · Pass the current location via the state prop on the Navigate component
The card recommends passing the current location in Navigate's state so the login flow can return the user to /dashboard after authentication. The replace prop only prevents an extra history entry; it does not store the intended destination, making D a common misconception.
Read the full bite: Implement a protected /dashboard route in React Router
Question 16 of 30
In React Router v6, how does a component rendered by /products/:productId correctly read the productId URL parameter?
Show the answer
Answer: d · Call useParams inside the component and read the productId property
useParams is the idiomatic v6 hook for reading dynamic segments, returning an object with keys like productId. props.match.params is the legacy v5 approach, manual parsing bypasses the router, and omitting the colon prefix creates a static route that only matches the literal string.
Read the full bite: How do you create a dynamic route like /products/:productId in React Router?
Question 17 of 30
When defining a dynamic UI route in Next.js, what is the fundamental difference between how Pages Router and App Router map the file system to the URL path?
Show the answer
Answer: d · App Router treats folders as route segments and requires page.js for the leaf UI, while Pages Router uses the JavaScript file itself as the route endpoint.
App Router uses folders as route segments and requires page.js for leaf UI, while Pages Router uses JavaScript files directly as route endpoints. Option C is tempting but wrong because App Router is not merely a folder rename; it introduces co-located segment-level primitives like layout.js and loading.js that Pages Router lacks.
Question 18 of 30
Which scenario most clearly justifies using useReducer instead of useState for React form state?
Show the answer
Answer: c · A multi-step wizard where country selection changes provinces, enables VAT, and triggers async tax lookups
The wizard's cascading interdependencies and async transitions are best centralized in a pure reducer; option D describes coupled fields appropriately managed by a single object with useState, not useReducer.
Read the full bite: Prefer multiple useState or useReducer for multi-field forms?
Question 19 of 30
When building real-time email validation in React, which state strategy best follows declarative, state-driven patterns?
Show the answer
Answer: d · Store the raw input in useState, use a single status enum such as typing or error, and derive validation during render.
The correct approach uses a single status enum and derives validation during render, avoiding redundant state. Option A is wrong because multiple boolean flags require manual synchronization and invite stale state bugs.
Read the full bite: How would you implement real-time client-side validation in React?
Question 20 of 30
How does React Hook Form primarily avoid re-rendering an entire form on every keystroke, compared to manual useState management?
Show the answer
Answer: d · It registers inputs via refs and treats them as uncontrolled, reading values only when needed.
React Hook Form attaches refs to inputs and keeps them uncontrolled so React does not render on every keystroke; values are read at validation or submission. The first option describes Formik's context-and-subscription strategy, which is a common point of confusion between the two libraries.
Read the full bite: Advantages of dedicated React form libraries over manual state
Question 21 of 30
You are building a Next.js newsletter form that must work without JavaScript and show server validation errors. Which pattern correctly wires the Server Action to the form?
Show the answer
Answer: b · Pass the Server Action to useFormState, place the bound action on the form's action prop, and read validation errors from the returned state
useFormState is designed for progressive enhancement by binding the returned action directly to the form's action attribute and surfacing server-returned state, whereas calling the action in onSubmit with useState breaks JavaScript-free submission and defeats the purpose of the hook.
Read the full bite: How do you use a Server Action for form submission and useFormState?
Question 22 of 30
A long-lived list component wraps a cheap per-item string format in useMemo. What net performance impact is most likely?
Show the answer
Answer: b · The aggregate cost of dependency comparisons and array allocations exceeds the cost of recomputing the format inline.
For cheap computations, the per-render cost of dependency checks and array allocations across many items typically exceeds recomputation, and cached values persist for the component's lifetime. Option A is tempting but wrong because useMemo alone does not prevent child re-renders unless the child is wrapped in React.memo.
Read the full bite: When can overusing useMemo hurt performance and what are the trade-offs?
Question 23 of 30
Which statement accurately describes the runtime behavior when a React.lazy component is first rendered within a Suspense boundary?
Show the answer
Answer: c · React invokes the loader on first render, caches the result, and Suspense displays a fallback until the Promise resolves.
React calls the lazy loader only on first render and caches both the Promise and resolved module, while Suspense catches the thrown Promise to show a fallback. Distractor A is wrong because lazy does not preload during module initialization; loading is deferred until the component is first rendered.
Read the full bite: How do React.lazy and dynamic import() enable code splitting?
Question 24 of 30
What mechanism allows Next.js to split routes into separate chunks without developers using React.lazy?
Show the answer
Answer: b · The file-system routing convention treats each page.js as an entry point, producing chunks at build time.
Next.js uses its file-system routing convention to make each page.js a discrete bundler entry point, automatically emitting separate chunks at build time. It does not rely on React.lazy under the hood, and prefetching is only an optimization that loads chunks already created by the routing contract.
Read the full bite: How does Next.js routing auto-implement code splitting?
Question 25 of 30
A Profiler reports actualDuration 80 ms and baseDuration 78 ms during an update. What does this suggest?
Show the answer
Answer: b · Memoization is failing and descendants are re-rendering unnecessarily
When actualDuration is nearly equal to baseDuration during an update, React is not skipping any descendants via memoization, so adding memo or useMemo should drop actualDuration while baseDuration remains high. Option C would be correct if baseDuration were high but actualDuration were low, indicating an inherently expensive subtree that is already being memoized.
Read the full bite: React Profiler long render duration: causes and next steps?
Question 26 of 30
A component only displays state.dashboard.theme, but its useSelector returns the entire dashboard object. It re-renders when unrelated dashboard data changes. What is the best fix?
Show the answer
Answer: a · Return state.dashboard.theme from the selector instead of the whole dashboard object
Returning the primitive theme allows strict equality checks to succeed when unrelated dashboard data changes, preventing extra re-renders. shallowEqual is tempting but still compares the full dashboard object, so it re-renders when widgets or layout change, while React.memo and store splitting treat symptoms instead of fixing selector granularity.
Read the full bite: How do you select a single property and prevent extra re-renders?
Question 27 of 30
What is the key architectural difference between handling async calls in Redux Toolkit versus Zustand?
Show the answer
Answer: a · Redux Toolkit auto-generates action lifecycles that reducers map to state, while Zustand leaves async structure up to the developer
Redux Toolkit's createAsyncThunk automatically produces pending, fulfilled, and rejected actions for reducers to handle, whereas Zustand stores rely on manual set calls inside plain async functions without an enforced pattern. Distractor A is tempting because beginners may not realize RTK generates those lifecycles automatically rather than requiring manual dispatch after each API call.
Read the full bite: How would you handle an async API call in Redux Toolkit versus Zustand?
Question 28 of 30
What fundamentally allows atomic state libraries to prevent unrelated component re-renders without requiring memoized selectors?
Show the answer
Answer: b · State is organized as a bottom-up graph where components subscribe only to the atoms they consume.
Atomic libraries structure state as a bottom-up graph where components subscribe to specific atoms, so updates to one atom only re-render its consumers. The mini-stores distractor mischaracterizes atoms as isolated Redux slices and misses the dependency graph and granular subscription model that actually prevents extra renders.
Read the full bite: Explain atomic state management and how it differs from Redux
Question 29 of 30
When testing a component that fetches data on mount, which approach correctly asserts the final rendered state without race conditions?
Show the answer
Answer: b · Mock the API, render the component, await screen.findByText for the final data, and assert the loading state with getByText if it renders synchronously.
B is correct because mocking isolates the test and findBy retries until the async data appears, while getBy is safe for the synchronous loading state. A is tempting but wrong because getBy throws if the element has not yet appeared after the initial render.
Read the full bite: Test a React component fetching async data on mount
Question 30 of 30
When unit testing a custom React hook like useCounter in isolation, what is the correct pattern to trigger and assert state updates?
Show the answer
Answer: b · Use renderHook, wrap the interaction in act, and read the updated state from result.current.
renderHook creates the component boundary hooks require, and act flushes state updates so result.current reflects the new value. D is tempting because it uses renderHook but skips act, leading to unflushed updates and React warnings.
Read the full bite: How do you unit test a custom React hook like useCounter?
Could you explain these out loud?
That is what an interview actually tests. Tezvyn gives you questions like these with what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.