skip to content

Built-in Hooks

You will learn the built-in hook APIs React ships — what each one's signature actually promises, how call order binds a hook to its state slot, and where the dependency array does and does not do what you expect. Interviewers spend a large share of a React screen here because almost every real bug (stale closures, missing cleanup, tearing, useless memoization) starts as a misread hook contract.

part ofReactoverview, primer and where to startread it →
on this pageshow

explore

questions

page 1 of 2

In React, from which functions may you call a hook such as useState, and which common call sites are forbidden?

level: juniorimportance: must knowfreq 70%

answer

  1. two legal bodies, nothing else
  2. the name is the signal
  3. handlers run after render, not during
  4. top level of the right function
  5. conditional arguments are fine

basics

~20 s

Hooks 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.

solid answer

~50 s

There are exactly two legal call sites: the body of a React function component, and the body of a custom hook — a function whose name starts with `use`, which React and the lint plugin both treat as hook-callable. Everything else is out: a click handler, a plain utility function the component calls, a `setTimeout` or `map` callback, the callback you pass to `useEffect`, and any class component method. Within a legal call site the call must also be at the top level: not inside an `if`, a loop, a `&&` or ternary, a `try`/`catch`/`finally` block, or below an early `return`. The reason both halves matter is the same — React identifies hooks by their call order within a rendering component, so a hook must run unconditionally, exactly once per render, from a function React is currently rendering.

go deeper

for a junior

Name the two legal bodies — a function component and a custom hook — and list the everyday illegal spots: event handlers, plain helpers, and callbacks. That answer alone passes this screener.

for a middle

Explain why each illegal site fails: no component is rendering at that moment, or the call count would vary. Point at the naming convention as the signal the lint rule keys on.

for a senior

Show the refactor you would apply in review — read at the top level and close over the value, or promote a helper to a properly named hook — and be able to say when a class component makes a hook migration a rewrite.

for a principal

Own the convention as an architectural contract: the use prefix is a public promise about a function's call constraints, and codebases that treat it loosely lose static enforcement across every consumer of that function.

## The two legal places **1. The top level of a function component.** A React function component is a function that returns JSX (by convention, capitalized). Hook calls belong directly in its body, before any early return. ```jsx function SearchBox({ query }) { const [text, setText] = useState(query); // legal useEffect(() => { report(text); }, [text]); // legal return <input value={text} onChange={(e) => setText(e.target.value)} />; } ``` **2. The body of another hook.** A function whose name begins with `use` followed by a capital letter is treated as a hook, and hooks may call other hooks. This is what makes custom hooks work at all: the calls inside them simply become part of the calling component's hook list, in the position where the custom hook was called. ```jsx function useOnlineStatus() { const [online, setOnline] = useState(navigator.onLine); // legal: inside a hook return online; } ``` ## The forbidden call sites, and why each fails **Event handlers.** `onClick={() => { const [x] = useState(0); }}` runs long after the render finished. No component is rendering at that moment, so there is no hook list to append to and no cursor to advance — React throws `Invalid hook call.` **The callback passed to useEffect.** Same reason: effect callbacks run after commit, outside render. `useEffect(() => { const value = useContext(Theme); }, [])` is illegal; read the context in the component body and let the effect close over the value. **Plain helper functions.** A function named `formatRow` or `getConfig` is not a component and not a hook, even if the component calls it during render. React cannot tell that its hook calls belong to the caller, and the lint rule flags it. The fix is either to rename it to `useSomething` (making it a real hook, subject to the same rules) or to pass the value in as an argument. **Class components.** Hooks were never wired into the class rendering path; a class has instance fields and lifecycle methods instead. A class cannot call a hook, which is why migrating a class to hooks is a rewrite of the component, not a line-level substitution. **Nested callbacks generally.** `array.map(item => useMemo(...))` is illegal on two counts: it is not a component or hook body, and the number of calls would vary with the array length — the exact instability the ordering scheme forbids. ## Top level, inside the legal site Being in the right function is only half the rule. Inside it, the call must be unconditional: ```jsx function Panel({ user }) { if (!user) return null; const [open, setOpen] = useState(false); // illegal: below an early return } ``` React's documented rules also exclude `try`/`catch`/`finally` blocks — a hook that throws mid-list would leave the list in an inconsistent state. Loops and conditional expressions (`cond && useMemo(...)`) are out for the same call-count reason. What is *not* forbidden is conditional data. `useState(user ? user.name : '')` and `useEffect(fn, [user?.id])` are both fine, because the call itself still runs on every render. ## How this gets enforced The `react-hooks/rules-of-hooks` rule in `eslint-plugin-react-hooks` reports these statically, using the naming convention as its signal: capitalized functions are components, `use`-prefixed functions are hooks, and anything else is neither. That is why the naming convention is load-bearing rather than cosmetic — call it `getWindowSize` instead of `useWindowSize` and the lint rule will report the `useState` inside it as an illegal call. It is configured as an error in the plugin's recommended config, because unlike a style rule, a violation is a real runtime defect. At runtime the enforcement is the dispatcher: React installs the current renderer's hook implementations only for the duration of a component's render, so a hook called from anywhere else finds nothing installed and throws.

  • Why does renaming a helper from getWindowSize to useWindowSize change whether hooks are allowed inside it?
    Because the `use` prefix is the convention React's tooling keys on. The lint rule classifies a `use`-prefixed function as a hook and permits hook calls inside it; anything else is treated as a plain function and its hook calls are reported. Renaming does not change runtime behaviour by itself — but it tells both the linter and human readers that the function must be called from a component or hook, at the top level.
  • I need a context value inside a click handler. Where does the useContext call go?
    In the component body, at the top level, and the handler closes over the result. Handlers run after the render that created them, when no component is rendering, so a hook call there throws. Reading during render and capturing the value in the handler is the standard shape for every hook you need inside an event callback.

saying these in an interview costs you the question

  • Says hooks work anywhere as long as the file exports a component
  • Thinks a hook is legal inside a useEffect callback
  • Believes any helper function called during render may use hooks
  • Claims class components can call hooks if they are wrapped
  • Treats the use-prefix naming convention as purely cosmetic

context

open as a page

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?

level: juniorimportance: must knowfreq 72%

basics

~20 s

createContext'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.

open as a page

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])?

level: juniorimportance: must knowfreq 85%

basics

~20 s

The 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.

open as a page

In React, what is the difference between useMemo(factory, deps) and useCallback(fn, deps), and how are the two related?

level: juniorimportance: must knowfreq 80%

basics

~10 s

useMemo 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).

open as a page

In React, what arguments does useReducer take and what does it return, and what happens when you call the dispatch function it gives you?

level: juniorimportance: must knowfreq 68%

basics

~20 s

useReducer 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.

open as a page

In React, what does useRef(initialValue) return, and why does assigning to ref.current not re-render the component the way a useState setter does?

level: juniorimportance: must knowfreq 82%

basics

~20 s

useRef returns a stable mutable object shaped { current: initialValue } that survives every render. Writing to .current mutates that object directly instead of going through React's update queue, so React is never notified and schedules no re-render.

open as a page

In React, what does the `useState` hook return, and why does assigning to the destructured state variable directly (for example `count = count + 1` inside a click handler) fail to update the UI?

level: juniorimportance: must knowfreq 85%

basics

~20 s

useState returns a two-item array: the state value for the render that is currently running, and a setter function. That value is an ordinary local binding, so assigning to it tells React nothing — only calling the setter schedules a re-render.

open as a page

In React 19, what does the useActionState(action, initialState) hook return, and what arguments does React pass to the action function when the returned action runs as a form's submit handler?

level: middleimportance: must knowfreq 60%

basics

~20 s

useActionState returns a three-element array: [state, formAction, isPending] — the action's most recent return value, an action to hand to a form's action prop, and a boolean that is true while it runs. React calls the action with (previousState, formData).

open as a page

A React 19 component renders <form action={submit}> and calls useFormStatus() in that same component to disable its button, but pending is always false. Why does that happen, and where must useFormStatus() be called instead?

level: middleimportance: must knowfreq 52%

basics

~20 s

useFormStatus reports on the nearest ancestor form, so a component that renders the form is not inside it and always sees pending false. Call the hook in a child component rendered within the form. It is exported by react-dom.

open as a page

In React, why must hooks be called in the same order on every render — what does React use to match a particular useState call to the state it returned last time?

level: middleimportance: must knowfreq 78%

basics

~20 s

React stores each component's hooks as an ordered list and matches every call to a slot by position alone — hook calls carry no names or keys. Change the call order and a hook reads another hook's slot.

open as a page

A React component must render nothing when its `user` prop is missing, but it also needs useState and useEffect. How do you satisfy the Rules of Hooks without running the effect's work for a missing user?

level: middleimportance: must knowfreq 62%

basics

~20 s

Put every hook call above the early return and branch inside the effect body, or lift the condition into the parent so the child component only mounts when a user exists. Never move a hook below the return.

open as a page

A React component both calls useContext(ThemeContext) and renders <ThemeContext value="dark"> around its own children. Which value does that component's own useContext call receive, and how does React resolve the lookup?

level: middleimportance: must knowfreq 58%

basics

~20 s

The component reads from the nearest provider above itself, or the context default if there is none. A provider it renders sits below it in the tree, so it affects the children only, never the component that renders it.

open as a page

A React component calls useEffect(() => { load(options); }, [options]) where const options = { page } is built in the component body. The effect re-runs on every render even when page never changes. Why?

level: middleimportance: must knowfreq 70%

basics

~20 s

React compares each dependency to the previous render's value with Object.is, and an object literal built during render is a brand-new reference every time, so the comparison always fails. Depend on the primitive page, or on a stable reference.

open as a page

In React, how does the timing of useLayoutEffect differ from useEffect, and what kind of bug makes you reach for useLayoutEffect?

level: middleimportance: must knowfreq 72%

basics

~20 s

useLayoutEffect runs synchronously after React updates the DOM but before the browser paints, so React blocks the paint until it finishes; useEffect is deferred until after paint. Reach for useLayoutEffect when a measure-then-adjust step would otherwise flash.

open as a page

In React, what does useMemo actually guarantee about the value it returns between renders, and what must the factory you pass it never do?

level: middleimportance: must knowfreq 62%

basics

~20 s

useMemo is a performance hint, not a semantic guarantee: React may throw the cached value away and call the factory again even when the dependencies are unchanged. The factory runs during render, so it must be pure — no side effects.

open as a page

A React component's reducer runs `state.items.push(item); return state;` and the list on screen never updates. Why does nothing re-render, and what rule is the reducer breaking?

level: middleimportance: must knowfreq 55%

basics

~20 s

The reducer mutated the existing state and returned the same object, so React's identity comparison sees no change and bails out of re-rendering. A reducer must be pure: never mutate the state it receives, and return a new object when anything changed.

open as a page

React 19's `use` may be called inside an `if` block or a loop, while `useState` may not. What about `use` makes that legal, and which placement rules still apply to it?

level: middleimportance: must knowfreq 58%

basics

~20 s

use() claims no per-component state slot — it just reads an already-existing resource — so skipping or repeating the call cannot misalign anything. It must still be called inside a component or custom Hook, and never inside try/catch.

open as a page

In a React component with `const [count, setCount] = useState(0)`, a click handler calls `setCount(count + 1)` three times in a row, yet each click only raises the count by one. Explain why, and what to write instead.

level: middleimportance: must knowfreq 78%

basics

~20 s

All three calls read the same count value from the current render, so all three request the same next value and the last one wins. Passing an updater function, setCount(c => c + 1), makes each call build on the previous result, giving plus three.

open as a page

A React page has a text input and a large list that re-renders slowly on every keystroke. Both useTransition and useDeferredValue can keep the input responsive — how do you decide which to use?

level: middleimportance: must knowfreq 62%

basics

~20 s

Use useTransition when you own the state update and can wrap the setter, since it also gives you an isPending flag. Use useDeferredValue when the slow render is driven by a value you only receive, or when you want the lag localized inside the slow component.

open as a page

In React, what does useDeferredValue(value) return during the render right after value changes, and what does React do next?

level: middleimportance: must knowfreq 58%

basics

~20 s

useDeferredValue returns the previous value on the render where value changes, so that render is fast. React then schedules a second, non-urgent background render with the new value, and that render can be interrupted and restarted if value changes again.

open as a page

A React component has grown to eight useState calls whose values always move together, and each handler now sets three or four of them in sequence. Would you convert it to useReducer, and what do you actually gain?

level: seniorimportance: must knowfreq 62%

basics

~20 s

Yes — that is the canonical signal. Coupled fields updated together belong in one reducer, which moves the transition logic out of the handlers into one pure function, makes impossible combinations unrepresentable, and gives you something you can unit-test without rendering.

open as a page

A React component keeps a list in state. A handler runs `items.push(newItem); setItems(items);` and the rendered list never changes. What comparison is React making, why does `setItems([...items, newItem])` work instead, and can you rely on that comparison as a performance optimisation?

level: seniorimportance: must knowfreq 66%

basics

~20 s

React compares the next state with the current one using Object.is. Pushing mutates the same array, so the reference is identical and React bails out. A new array from the spread is a different reference, so the update is seen. Treat the bail-out as a courtesy, not a guarantee.

open as a page

In React 19, when you pass a function to a form element's action prop (<form action={saveNote}>), what single argument does React call that function with, and what does React do to the form's uncontrolled inputs after the function finishes?

level: juniorimportance: should knowfreq 45%

basics

~20 s

React calls the function with one argument, a FormData object built from the form's named fields. There is no submit event, so nothing to preventDefault. After the function finishes, React automatically resets the form's uncontrolled inputs.

open as a page

In React 19, what is the difference between rendering <ThemeContext value={theme}> and <ThemeContext.Provider value={theme}>, and which form is current?

level: juniorimportance: should knowfreq 42%

basics

~20 s

They behave identically. React 19 lets the context object itself be rendered as a provider, so <ThemeContext value={theme}> is the current form. <ThemeContext.Provider> still works and remains valid, with deprecation announced for a future release.

open as a page

In React 19, a client component runs `const data = use(dataPromise)` where `dataPromise` arrived as a prop. What does that call evaluate to, and what does React do with the component while the promise is still pending?

level: juniorimportance: should knowfreq 52%

basics

~10 s

use(dataPromise) returns the value the promise fulfilled with. While the promise is pending, React suspends the component and shows the nearest Suspense boundary's fallback, so the component itself holds no loading state.

open as a page

What problem does React's useId hook solve, and why are a module-level counter or Math.random() bad substitutes for it?

level: juniorimportance: should knowfreq 50%

basics

~20 s

useId generates a unique string id that is identical on the server and on the client, so attributes like htmlFor and aria-describedby survive hydration. A random value differs between the two renders, and a module counter depends on render order, so both can produce mismatched markup.

open as a page

In React, what does calling useTransition() give you, and what does the isPending value it returns tell you?

level: juniorimportance: should knowfreq 52%

basics

~20 s

useTransition() returns a two-item array, [isPending, startTransition]. State updates triggered inside the startTransition callback are marked non-urgent so React can let urgent input go first, and isPending is true while such an update is still rendering.

open as a page

In React 19, what are the two arguments to useOptimistic, what does it return, and at what moment does the optimistic value stop being rendered?

level: middleimportance: should knowfreq 42%

basics

~10 s

useOptimistic(state, updateFn) returns [optimisticState, addOptimistic]. Calling addOptimistic(value) inside an action immediately renders updateFn(currentState, value); when that action settles React drops the optimistic layer and renders the real state argument again.

open as a page

In React, why does passing an async function directly to useEffect break, and how do you await something inside an effect instead?

level: middleimportance: should knowfreq 60%

basics

~20 s

The return value of a useEffect callback is reserved for the cleanup function, and an async function always returns a Promise, so React warns and you lose cleanup. Declare an async function inside the effect and call it.

open as a page

In React, you wrapped a handler in useCallback but the child still receives a brand-new function on every render. What comparison does React run on the dependency array, and what usually defeats it?

level: middleimportance: should knowfreq 58%

basics

~20 s

React compares each dependency positionally against the previous render's array using Object.is, and returns the new function if any entry differs. A dependency allocated fresh each render — an inline object, array or unmemoized callback — never compares equal, so the cache always misses.

open as a page

showing 1–30 of 52