Why pass a function to useState for expensive initial values?

This tests your understanding of React's render-phase behavior. Without the function, expensive work reruns on every render and is thrown away; the initializer runs once only during mount.
What's really being asked
This question probes whether you understand the boundary between React's initialization phase and its render phase. It checks if you know that useState receives its initial argument expression during every render but only applies it on the first mount, and whether you can articulate why lazy initialization matters for performance and correctness. Interviewers want to hear that you think about work that happens inside the render path.
The full answer
First, the direct call computeExpensiveValue(props) executes on every render because JavaScript evaluates arguments before invoking the Hook. React ignores the returned value after the first mount, so the work is completely wasted. Second, the initializer function form useState(() => computeExpensiveValue(props)) is called only once by React during the initial render, and its return value is stored as the state. Third, the initializer must be pure and must take no arguments, because React may call it twice in Strict Mode during development and will discard one of the results. Fourth, this pattern is distinct from useMemo; useMemo still runs during every render to compare dependencies, whereas the initializer is strictly mount-only and avoids even that overhead.
The mistakes people make
Saying the function form prevents re-renders. Claiming it is merely syntactic sugar or a style preference without mentioning wasted computation on every render. Confusing the initializer with the updater function form of setState. Asserting that the initializer receives props or arguments, which the API explicitly does not support. Arguing that useMemo is the better tool here without acknowledging that useMemo still executes during render and incurs dependency comparison overhead. Saying React calls the initializer on every render but caches the result, which is false.
What usually comes next
How does Strict Mode affect the initializer function, and why does React call it twice in development? What happens if the initializer is not pure? Why not just use useMemo instead? How would you initialize state from expensive props-derived data without repeating the work? What is the real performance cost if the computation takes 50 milliseconds and the component re-renders ten times? When is lazy initialization unnecessary?
A concrete example
Imagine a dashboard widget that parses a two-megabyte JSON blob to build a lookup map. Calling useState(buildMap(data)) executes the parser on every render, costing 40 milliseconds each time even though React throws the result away after the first call. With useState(() => buildMap(data)), React invokes the arrow function once during mount, stores the map, and never calls it again. Over ten re-renders triggered by hover or polling updates, the lazy version saves 400 milliseconds of main-thread work and avoids jank.
Interview question
What is the key difference between useState(expensive()) and useState(() => expensive()) during re-renders?
- a.The direct call executes on every render but React discards its result after mount, while the function runs only once during initialization.Correct
- b.The direct call is automatically memoized by React after the first render, while the function form executes on every render to compare dependencies.
- c.The function receives the previous state as an argument, allowing React to skip calling it if the state already exists.
- d.The function form prevents the component from re-rendering when parent state changes by stabilizing the initial value reference.
Why? this is the answer
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.
Just read this? Test yourself on what you have been reading.
Read the original → react.dev
- #react
- #usestate
- #hooks
- #performance
- #initialization
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you 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.
We are hiring for this. Open roles that interview on react — each one lists the topics its interview covers.
See open roles