Interview questionsReact
React interview questions and answers
30 React questions picked from Codejump's quizzes, from the basics a junior is expected to know to the details that trip up senior candidates. Each one comes with its answer and an explanation — try to answer before you open it.
Junior level React questions
1.Which renders the
<Alert />component only whenhasErroris true?javascript// Option A: {hasError && <Alert />} // Option B: {hasError ? <Alert /> : null} // Option C: {hasError ? <Alert /> : undefined} // Option D: All of the above- A.Only option A
- B.Only option B
- C.Only option A and B
- D.All three options (A, B, C) render <Alert /> when true and nothing when false
Show answer
Answer: D. All three options (A, B, C) render <Alert /> when true and nothing when false
React renders nothing fornull,undefined, andfalse: All three are semantically equivalent. Option A (&&) is the most concise and common pattern.From the quiz React Basics
2.How do you access a DOM element with
useRef?javascriptfunction FocusInput() { const inputRef = useRef(null); const handleClick = () => { inputRef.current.focus(); // (A) }; return ( <> <input ref={inputRef} type="text" /> <button onClick={handleClick}>Focus</button> </> ); }- A.This is wrong — useRef doesn't work with DOM elements
- B.inputRef.current is the React element, not the DOM element
- C.ref={inputRef} attaches the ref to the <input> DOM node; after mount, inputRef.current is the actual DOM element — .focus() calls the native DOM method
- D.You need document.querySelector("input") instead — refs don't give DOM access
Show answer
Answer: C. ref={inputRef} attaches the ref to the <input> DOM node; after mount, inputRef.current is the actual DOM element — .focus() calls the native DOM method
React assignsref.currentto the DOM node after the component mounts. Before mount (during render), it's stillnull.From the quiz Core Hooks
3.Which state is unnecessary here?
javascriptfunction CartSummary({ items }) { // Is this state or derived? const [total, setTotal] = useState(0); useEffect(() => { setTotal(items.reduce((sum, item) => sum + item.price * item.quantity, 0)); }, [items]); return <p>Total: ${total}</p>; }- A.total is derived from items — it should be computed during render, not stored in state; the useEffect adds an extra render cycle unnecessarily
- B.total should be state — it changes when items change
- C.This pattern is correct — useEffect is the right place to compute totals
- D.You should use useReducer for totals
Show answer
Answer: A. total is derived from items — it should be computed during render, not stored in state; the useEffect adds an extra render cycle unnecessarily
Rule: if a value can be computed from props or other state, don't store it in state.From the quiz Rendering Basics
4.When is the default context value used?
javascriptconst CounterContext = createContext(0); // default: 0 function CounterDisplay() { const count = useContext(CounterContext); return <p>Count: {count}</p>; } // Scenario A: Wrapped in Provider: <CounterContext.Provider value={42}> <CounterDisplay /> {/* count = ? */} </CounterContext.Provider> // Scenario B: Not wrapped: <CounterDisplay /> {/* count = ? */}- A.Scenario A: 0, Scenario B: 42
- B.Both scenarios return 0
- C.Scenario A: error, Scenario B: 0
- D.Scenario A: 42, Scenario B: 0 — the default is used only when no Provider is found in the parent tree
Show answer
Answer: D. Scenario A: 42, Scenario B: 0 — the default is used only when no Provider is found in the parent tree
The default value is useful for: 1. Testing components in isolation (no Provider needed) 2. Library components that work without a ProviderFrom the quiz Local State & Lifting
5.What is the purpose of the
keyprop?javascriptfunction List({ items }) { return ( <ul> {items.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> ); }- A.key helps React identify which items changed, added, or removed — enabling efficient DOM updates
- B.key is passed as a prop to the <li> component and can be accessed as props.key
- C.key is required for styling purposes — React won't render without it
- D.key must be a number — strings are not accepted
Show answer
Answer: A. key helps React identify which items changed, added, or removed — enabling efficient DOM updates
keyis a special React prop used for the reconciliation algorithm. When a list re-renders, React uses keys to match old elements to new ones:From the quiz React Basics
6.How do you consume context with
useContext?javascriptconst ThemeContext = createContext("light"); function ThemedButton() { const theme = useContext(ThemeContext); return <button className={`btn-${theme}`}>Click</button>; } function App() { return ( <ThemeContext.Provider value="dark"> <ThemedButton /> </ThemeContext.Provider> ); }- A.ThemedButton receives "light" (the default) — Provider doesn't override it
- B.useContext requires a second argument specifying which provider to use
- C.ThemedButton receives "dark" — useContext reads the nearest Provider's value; the default "light" is only used when there's no Provider
- D.Context only works with class components — useContext returns undefined in functions
Show answer
Answer: C. ThemedButton receives "dark" — useContext reads the nearest Provider's value; the default "light" is only used when there's no Provider
React looks up the component tree to find the nearestThemeContext.Provider. The default value is the fallback when no provider is found.From the quiz Core Hooks
7.What is the performance impact of images in React?
javascript// ❌ Unoptimized: <img src="/hero.png" /> {/* 2MB PNG */} // ✅ Better (Next.js Image component): import Image from "next/image"; <Image src="/hero.png" width={800} height={600} alt="Hero" priority /> // ✅ Without Next.js: <img src="/hero-800.webp" srcSet="/hero-400.webp 400w, /hero-800.webp 800w" sizes="(max-width: 600px) 400px, 800px" loading="lazy" alt="Hero" />- A.Images don't affect React performance — they're handled by the browser
- B.loading="lazy" prevents the image from ever loading
- C.Images are often the largest assets — unoptimized images hurt LCP (Largest Contentful Paint); optimizations: correct format (WebP), lazy loading, proper sizing, responsive srcSet
- D.Next.js Image component requires a paid plan
Show answer
Answer: C. Images are often the largest assets — unoptimized images hurt LCP (Largest Contentful Paint); optimizations: correct format (WebP), lazy loading, proper sizing, responsive srcSet
Image optimization impacts:From the quiz Rendering Basics
8.What is the correct way to compose multiple Contexts?
javascriptfunction App() { const [theme, setTheme] = useState("light"); const [user, setUser] = useState(null); const [locale, setLocale] = useState("en"); return ( <ThemeContext.Provider value={{ theme, setTheme }}> <UserContext.Provider value={{ user, setUser }}> <LocaleContext.Provider value={{ locale, setLocale }}> <AppContent /> </LocaleContext.Provider> </UserContext.Provider> </ThemeContext.Provider> ); }- A.Multiple Contexts are bad — combine them into one
- B.Multiple focused Contexts are preferred — ThemeContext consumers only re-render on theme changes; UserContext consumers only re-render on user changes; separation of concerns
- C.Nested Providers cause performance issues — use a flat structure
- D.You can only have one Context per application
Show answer
Answer: B. Multiple focused Contexts are preferred — ThemeContext consumers only re-render on theme changes; UserContext consumers only re-render on user changes; separation of concerns
Each consumer only subscribes to its relevant context: If you combined everything into oneAppContext, EVERY consumer would re-render on ANY change.From the quiz Local State & Lifting
9.What is the correct way to handle a button click?
javascript// Option A: <button onClick={handleClick()}>Click</button> // Option B: <button onClick={handleClick}>Click</button> // Option C: <button onClick={() => handleClick()}>Click</button> // Option D: B and C are both correct- A.Only option A — parentheses invoke the function
- B.Only option B — pass the function reference
- C.Only option C — arrow function wrapper is required
- D.B and C are both correct — B passes the function reference, C wraps it in an arrow function
Show answer
Answer: D. B and C are both correct — B passes the function reference, C wraps it in an arrow function
- Option A (
onClick={handleClick()}) callshandleClickimmediately during render — not on click. The return value ofhandleClick(usuallyundefined) is passed as the handler. Almost always a bug. - Option B (
onClick={handleClick}) passes the function reference — React calls it when clicked. - Option C (
onClick={() => handleClick()}) wraps in an arrow function — useful when you need to pass arguments:onClick={() => handleClick(item.id)}.
From the quiz React Basics
10.Which code violates the Rules of Hooks?
javascript// Option A: function Component({ isAdmin }) { if (isAdmin) { const [role, setRole] = useState("admin"); // ❌? } return <div />; } // Option B: function Component({ isAdmin }) { const [role, setRole] = useState(isAdmin ? "admin" : "user"); // ✅? return <div />; }- A.Both options are valid React patterns
- B.Option A violates the Rules of Hooks — hooks must not be called inside conditionals/loops; Option B is correct — hooks always called, initial value uses the condition
- C.Option B is invalid — useState can't accept expressions
- D.Both options are invalid — isAdmin can't be used inside a component
Show answer
Answer: B. Option A violates the Rules of Hooks — hooks must not be called inside conditionals/loops; Option B is correct — hooks always called, initial value uses the condition
Rule: Hooks must be called at the top level — not insideif,for, nested functions. Why? React relies on the order of hook calls to associate state with the right hook:From the quiz Core Hooks
Mid level React questions
11.What is wrong with this pattern?
javascriptfunction UserProfile({ user }) { // ❌ Anti-pattern: copying props into state const [displayName, setDisplayName] = useState(user.firstName + " " + user.lastName); return <h2>{displayName}</h2>; }- A.Nothing — storing derived values in state is correct
- B.The concatenation should be in useEffect, not useState
- C.displayName won't update when user prop changes — state only initializes once; this is the "stale state from props" anti-pattern
- D.useState doesn't accept string expressions
Show answer
Answer: C. displayName won't update when user prop changes — state only initializes once; this is the "stale state from props" anti-pattern
useStateonly uses the initial value on the first render. Ifuserprop changes,displayNamestate is not updated:From the quiz Component Patterns
12.What makes a custom hook a "hook"?
javascriptfunction useFetch(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetch(url) .then(res => res.json()) .then(data => { setData(data); setLoading(false); }); }, [url]); return { data, loading }; } // Usage: const { data, loading } = useFetch("/api/users");- A.Custom hooks must use a class that extends React.Hook
- B.Custom hooks can only be used once per component
- C.A custom hook is just a JavaScript function that calls other hooks (starts with use by convention) — it extracts reusable stateful logic while keeping hook rules
- D.Custom hooks must return JSX
Show answer
Answer: C. A custom hook is just a JavaScript function that calls other hooks (starts with use by convention) — it extracts reusable stateful logic while keeping hook rules
A custom hook is any function that: 1. Starts withuse(convention enforced by linters) 2. Calls at least one React hook internallyFrom the quiz Custom Hooks
13.When should you choose Zustand over local
useState?javascript// Scenario: Shopping cart // - Cart icon in Header shows item count // - Cart page shows all items // - Checkout page reads cart total // - Product cards have "Add to cart" button // useState in each component? Or Zustand?- A.Zustand is better here: cart is cross-component (Header, Cart, Checkout, ProductCards); all need to read/write the same data; lifting state 4+ levels deep is painful
- B.Always use Zustand — it's always better than useState
- C.Use useState in Header and pass via props everywhere
- D.Create a custom hook with useState inside and export it
Show answer
Answer: A. Zustand is better here: cart is cross-component (Header, Cart, Checkout, ProductCards); all need to read/write the same data; lifting state 4+ levels deep is painful
When Zustand wins:From the quiz Context & Reducers
14.What is "prop drilling" and why is it a problem?
javascriptfunction App() { const [user, setUser] = useState({ name: "Alice", role: "admin" }); return <Dashboard user={user} />; } function Dashboard({ user }) { return <Sidebar user={user} />; // passes user but doesn't use it } function Sidebar({ user }) { return <UserBadge user={user} />; // passes user but doesn't use it } function UserBadge({ user }) { return <span>{user.name}</span>; // finally uses user }- A.Dashboard and Sidebar receive user only to pass it down — they don't need it. This "prop drilling" creates unnecessary coupling and makes refactoring harder
- B.No problem — this is the correct React data flow
- C.Error — React only allows 2 levels of prop passing
- D.This causes performance issues because all components re-render
Show answer
Answer: A. Dashboard and Sidebar receive user only to pass it down — they don't need it. This "prop drilling" creates unnecessary coupling and makes refactoring harder
Prop drilling = passing props through intermediate components that don't use them — just to get data to a deeply nested component. Problems:- Coupling:
DashboardandSidebarare coupled tousers shape even though they dont use it - Refactoring: adding/removing a prop requires touching every intermediate component
- Readability: harder to see where data flows Solutions: 1. Context API — for global/shared state 2. Component composition — restructure to avoid intermediate passing 3. State management (Zustand, etc.)
From the quiz Component Patterns
15.What is the bug in this code?
javascriptfunction Timer({ initialCount }) { const [count, setCount] = useState(initialCount); useEffect(() => { const interval = setInterval(() => { setCount(count + 1); // ← bug? }, 1000); return () => clearInterval(interval); }, []); // empty deps return <p>{count}</p>; }- A.Stale closure bug: count inside the setInterval callback is captured at the initial render (always initialCount) — the count will never increment past initialCount + 1
- B.No bug — the timer correctly increments every second
- C.The return cleanup is incorrect — you can't return from an async callback
- D.setInterval is not allowed in React
Show answer
Answer: A. Stale closure bug: count inside the setInterval callback is captured at the initial render (always initialCount) — the count will never increment past initialCount + 1
Fix with functional update — no closure overcount:From the quiz Custom Hooks
16.What is the recommended approach for form state?
javascript// Option A — controlled with useState: const [name, setName] = useState(""); const [email, setEmail] = useState(""); <input value={name} onChange={e => setName(e.target.value)} /> // Option B — uncontrolled with useRef: const nameRef = useRef(); // <input ref={nameRef} defaultValue="" /> // Option C — react-hook-form: const { register, handleSubmit } = useForm(); // <input {...register("name")} />- A.Always use uncontrolled inputs — controlled inputs are slow
- B.For simple forms: Option A or B work; for complex forms (many fields, validation, submission), react-hook-form (Option C) is preferred — it minimizes re-renders by default
- C.Never use uncontrolled inputs — they're unidiomatic in React
- D.Forms must always use Zustand store
Show answer
Answer: B. For simple forms: Option A or B work; for complex forms (many fields, validation, submission), react-hook-form (Option C) is preferred — it minimizes re-renders by default
| Approach | Best for | Performance | |---|---|---| |useState(controlled) | Simple forms, real-time validation | Re-renders on each keystroke | |useRef(uncontrolled) | Simple forms, no real-time feedback | No re-renders | |react-hook-form| Complex forms, schemas, dynamic fields | Minimal re-renders |From the quiz Context & Reducers
17.What happens when you change the
keyof a component?javascriptfunction App() { const [userId, setUserId] = useState(1); return ( <> <UserProfile key={userId} userId={userId} /> <button onClick={() => setUserId(2)}>Switch User</button> </> ); } function UserProfile({ userId }) { const [bio, setBio] = useState(""); // fetches and displays user bio }- A.Changing key only triggers a re-render without affecting component state
- B.Changing key causes an error because key is read-only
- C.key only affects list items — it has no effect on standalone components
- D.Changing key causes React to unmount the old instance and mount a completely new one — state is reset to initial values
Show answer
Answer: D. Changing key causes React to unmount the old instance and mount a completely new one — state is reset to initial values
When a component'skeychanges, React treats it as a different component: This is the recommended way to reset component state when a prop changes — much cleaner than tracking changes inuseEffect.From the quiz Component Patterns
18.What is the difference between
useEffectanduseLayoutEffect?javascriptfunction Tooltip({ position }) { const tooltipRef = useRef(null); const [adjustedTop, setAdjustedTop] = useState(position.top); useLayoutEffect(() => { const height = tooltipRef.current.getBoundingClientRect().height; if (position.top + height > window.innerHeight) { setAdjustedTop(position.top - height); // flip tooltip } }, [position]); return <div ref={tooltipRef} style={{ top: adjustedTop }}>...</div>; }- A.useLayoutEffect and useEffect are identical — same timing
- B.useLayoutEffect is deprecated — always use useEffect instead
- C.useLayoutEffect fires SYNCHRONOUSLY after DOM mutations but BEFORE the browser paints — ideal for DOM measurements and immediate corrections (no flicker); useEffect fires after paint
- D.useLayoutEffect runs before the component renders
Show answer
Answer: C. useLayoutEffect fires SYNCHRONOUSLY after DOM mutations but BEFORE the browser paints — ideal for DOM measurements and immediate corrections (no flicker); useEffect fires after paint
WithuseEffectinstead:From the quiz Custom Hooks
19.What is Jotai's atomic state model?
javascriptimport { atom, useAtom } from "jotai"; const countAtom = atom(0); const doubleAtom = atom(get => get(countAtom) * 2); // derived atom function Counter() { const [count, setCount] = useAtom(countAtom); return <button onClick={() => setCount(c => c + 1)}>{count}</button>; } function DoubleCount() { const [double] = useAtom(doubleAtom); return <p>Double: {double}</p>; // automatically updates }- A.All components sharing countAtom are in the same React tree
- B.Jotai requires a Provider like Context
- C.Atoms are independent units of state — derived atoms automatically recompute when their dependencies change; components subscribe to specific atoms, not a global object
- D.doubleAtom causes two separate API calls
Show answer
Answer: C. Atoms are independent units of state — derived atoms automatically recompute when their dependencies change; components subscribe to specific atoms, not a global object
Jotai's model: vs Zustand: Jotai works bottom-up (atom per state unit) vs Zustand's top-down (one store object).From the quiz Context & Reducers
20.What happens when you try to render an object directly?
javascriptconst user = { name: "Alice", age: 30 }; function App() { return <div>{user}</div>; // ? }- A.Renders [object Object]
- B.React error: "Objects are not valid as a React child"
- C.Renders { name: "Alice", age: 30 }
- D.Renders nothing — objects are silently ignored
Show answer
Answer: B. React error: "Objects are not valid as a React child"
React cannot render plain objects as children. It throws: Valid React child types: strings, numbers, booleans, null, undefined, arrays of these, or React elements.From the quiz Component Patterns
Senior level React questions
21.Why does React StrictMode call component functions twice in development?
javascriptfunction App() { console.log("App rendered"); // appears twice in console return <div>Hello</div>; } ReactDOM.createRoot(document.getElementById("root")).render( <React.StrictMode> <App /> </React.StrictMode> );- A.A bug in React's development mode
- B.This behavior also occurs in production
- C.StrictMode renders components twice for visual consistency
- D.StrictMode intentionally double-invokes functions to detect side effects — components should be pure functions (same output for same input); double invocation surfaces violations
Show answer
Answer: D. StrictMode intentionally double-invokes functions to detect side effects — components should be pure functions (same output for same input); double invocation surfaces violations
React StrictMode double-invokes (in development only):- Function components
useStateinitializer functionsuseMemofunctionsuseReducerreducers Why: To detect unintentional side effects. Pure functions produce the same result when called twice. If your component logs, fetches, or mutates external state during render — that's a bug StrictMode will expose:
From the quiz Advanced Patterns
22.What is the advantage of action payloads in
useReducer?javascriptconst reducer = (state, action) => { switch (action.type) { case "FETCH_SUCCESS": return { ...state, data: action.payload, loading: false, error: null }; case "FETCH_ERROR": return { ...state, error: action.payload, loading: false }; case "RETRY": return { ...state, loading: true, error: null, retries: state.retries + 1 }; default: return state; } }; dispatch({ type: "FETCH_SUCCESS", payload: data }); dispatch({ type: "FETCH_ERROR", payload: new Error("Network failed") });- A.Action payloads are optional and rarely used
- B.Payloads carry data for the transition — the reducer produces a new state from (currentState, action) deterministically; this makes transitions testable and predictable without component context
- C.You can only have one active action type at a time
- D.useReducer actions must be pure strings
Show answer
Answer: B. Payloads carry data for the transition — the reducer produces a new state from (currentState, action) deterministically; this makes transitions testable and predictable without component context
The reducer pattern:From the quiz Advanced Hook Patterns
23.What does Immer enable in state management?
javascriptimport { produce } from "immer"; const reducer = (state, action) => { return produce(state, draft => { switch (action.type) { case "ADD_COMMENT": // Nested update — looks like mutation, produces new state: draft.posts[action.postId].comments.push(action.comment); break; case "MARK_READ": draft.notifications.forEach(n => { n.read = true; }); break; } }); };- A.Immer's produce creates a structural clone ("draft") — any mutations on the draft produce a new immutable state; the original state is never modified
- B.produce actually mutates the original state
- C.Immer is slower than spreading nested objects manually
- D.Immer requires all state to be serializable JSON
Show answer
Answer: A. Immer's produce creates a structural clone ("draft") — any mutations on the draft produce a new immutable state; the original state is never modified
Without Immer — deep nested updates are verbose: Immer uses JavaScript Proxies to track mutations and creates a minimal structural copy.From the quiz Global State
24.What is a React Portal used for?
javascriptimport { createPortal } from "react-dom"; function Modal({ isOpen, children }) { if (!isOpen) return null; return createPortal( <div className="modal-overlay">{children}</div>, document.getElementById("modal-root") ); }- A.Portals allow rendering in a Web Worker outside the main thread
- B.Portals render children into a different DOM node than the component's parent — useful for modals, tooltips, dropdowns that need to escape CSS overflow/z-index constraints
- C.Portals create a separate React tree that doesn't receive context from the parent
- D.Portals are required for server-side rendering
Show answer
Answer: B. Portals render children into a different DOM node than the component's parent — useful for modals, tooltips, dropdowns that need to escape CSS overflow/z-index constraints
Portals render children into a different DOM location, but the React tree hierarchy is preserved: The modal escapesoverflow: hiddenconstraints of its ancestors while staying in React's tree for events, context, and state.From the quiz Advanced Patterns
25.What causes the infinite loop?
javascriptfunction Component() { const [items, setItems] = useState([]); useEffect(() => { const processed = items.map(item => ({ ...item, processed: true })); setItems(processed); // ← triggers re-render → effect runs again → infinite! }, [items]); // items is a dependency }- A.setItems(processed) creates a new array reference → items dependency changes → effect runs again → infinite loop; the state update triggers the effect that triggered the state update
- B.This is fine — React detects circular updates and stops automatically
- C.The issue is using .map() inside useEffect
- D.Setting state in useEffect is always prohibited
Show answer
Answer: A. setItems(processed) creates a new array reference → items dependency changes → effect runs again → infinite loop; the state update triggers the effect that triggered the state update
Fixes:From the quiz Advanced Hook Patterns
26.How should you categorize state?
javascript// Server state examples: const { data: users } = useQuery({ queryKey: ["users"], queryFn: fetchUsers }); const { data: profile } = useQuery({ queryKey: ["profile"], queryFn: fetchProfile }); // Client state examples: const [isModalOpen, setIsModalOpen] = useState(false); const [selectedTab, setSelectedTab] = useState("overview");- A.Server state (lives on server, fetched async, can be stale): use React Query/SWR/RTK Query; Client state (lives in browser, user-controlled): use useState/Zustand; they have different characteristics and needs
- B.All state should be managed the same way
- C.Server state should be stored in Zustand after fetching
- D.You should never cache server state in the client
Show answer
Answer: A. Server state (lives on server, fetched async, can be stale): use React Query/SWR/RTK Query; Client state (lives in browser, user-controlled): use useState/Zustand; they have different characteristics and needs
| | Server State | Client State | |---|---|---| | Lives in | Database/API | Browser memory | | Asynchronous | ✅ Always | ❌ Usually sync | | Can be stale | ✅ Yes | ❌ Always fresh | | Shared by | Many users | One user/session | | Tools | React Query, RTK Query | useState, Zustand |From the quiz Global State
27.Why is cleanup important in
useEffect?javascriptuseEffect(() => { const subscription = eventBus.subscribe("update", handler); return () => { subscription.unsubscribe(); // cleanup }; }, []);- A.Cleanup is optional — React garbage-collects all subscriptions automatically
- B.Cleanup only runs when the effect dependencies change, not on unmount
- C.Without cleanup, subscriptions/intervals persist after the component unmounts — causing memory leaks and calling state updates on unmounted components
- D.Cleanup runs before each render, not just on unmount
Show answer
Answer: C. Without cleanup, subscriptions/intervals persist after the component unmounts — causing memory leaks and calling state updates on unmounted components
Without cleanup: With cleanup: The cleanup function runs: 1. Before the effect runs again (when deps change) 2. When the component unmountsFrom the quiz Advanced Patterns
28.Why use
useReffor a callback that needs fresh state?javascriptfunction useEventCallback(callback) { const callbackRef = useRef(callback); useLayoutEffect(() => { callbackRef.current = callback; }); return useCallback(() => { callbackRef.current(); }, []); // stable reference! }- A.This pattern is unnecessary — useCallback with deps solves the same problem
- B.useLayoutEffect is wrong here — should use useEffect
- C.This creates a stable function reference (empty useCallback deps) while the callback inside always reads the latest closure — solving the "stale callback but need fresh state" tradeoff
- D.This pattern violates Rules of Hooks
Show answer
Answer: C. This creates a stable function reference (empty useCallback deps) while the callback inside always reads the latest closure — solving the "stale callback but need fresh state" tradeoff
The dilemma: This pattern is used in React documentation and libraries likereact-use.From the quiz Advanced Hook Patterns
29.What is the full optimistic update pattern with React Query?
javascriptconst mutation = useMutation({ mutationFn: (newTodo) => api.createTodo(newTodo), onMutate: async (newTodo) => { await queryClient.cancelQueries({ queryKey: ["todos"] }); const previousTodos = queryClient.getQueryData(["todos"]); queryClient.setQueryData(["todos"], old => [...old, { ...newTodo, id: "temp" }]); return { previousTodos }; // context for rollback }, onError: (err, newTodo, context) => { queryClient.setQueryData(["todos"], context.previousTodos); // rollback! }, onSettled: () => { queryClient.invalidateQueries({ queryKey: ["todos"] }); // refetch }, });- A.Rollback is not possible with React Query
- B.onMutate saves the previous state and applies the optimistic update; onError rolls back to the saved state; onSettled ensures the server is the source of truth with a refetch
- C.cancelQueries cancels the mutation itself
- D.Optimistic updates require Redux Toolkit to work
Show answer
Answer: B. onMutate saves the previous state and applies the optimistic update; onError rolls back to the saved state; onSettled ensures the server is the source of truth with a refetch
The lifecycle:From the quiz Global State
30.What is the performance issue with this Context pattern?
javascriptconst ThemeContext = createContext(null); function App() { const [theme, setTheme] = useState("light"); const [user, setUser] = useState({ name: "Alice" }); return ( <ThemeContext.Provider value={{ theme, setTheme, user, setUser }}> <DeepTree /> </ThemeContext.Provider> ); }- A.No issue — Context is always efficient
- B.Every time user changes, ALL context consumers re-render — even those that only use theme. The entire value object is recreated each render
- C.Context only works one level deep
- D.setTheme and setUser cause circular updates
Show answer
Answer: B. Every time user changes, ALL context consumers re-render — even those that only use theme. The entire value object is recreated each render
Context uses reference equality for change detection. A new object{ theme, setTheme, user, setUser }is created on every render: Solutions:From the quiz Advanced Patterns
Practise 500+ more React questions
Timed quizzes with instant feedback, the questions you miss coming back until they stick, coding challenges and AI mock interviews — free to start.