[{"data":1,"prerenderedAt":178},["ShallowReactive",2],{"qa-\u002Freact\u002Fhooks\u002Fusestate":3},{"page":4,"siblings":170,"blog":175},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"related":161,"seo":162,"seoDescription":163,"stem":164,"subtopic":165,"topic":166,"topicSlug":167,"updated":168,"__hash__":169},"qa\u002Freact\u002Fhooks\u002Fusestate.md","Usestate",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"easy","md","React","react",{},true,1,"\u002Freact\u002Fhooks\u002Fusestate",[23,27,32,36,40,44,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157],{"id":24,"difficulty":14,"q":25,"a":26},"what-is-usestate","What does useState return?","`useState` returns an array of exactly two elements: the **current state\nvalue** for this render, and a **setter function** that schedules an update\nand triggers a re-render. You destructure them, and the `[value, setValue]`\nnaming convention is just that — a convention, not something React enforces.\n\n```jsx\nconst [count, setCount] = useState(0)\n\u002F\u002F     ▲ current value  ▲ setter that re-renders with the next value\n```\n\nA few things that trip people up in interviews:\n\n- The argument (`0` here) is only the **initial** value. On every render\n  after the first, React ignores it and hands you the latest stored value.\n- The setter has a **stable identity** — React guarantees it never changes\n  between renders, so it's safe to omit from `useEffect`\u002F`useCallback`\n  dependency arrays.\n- Calling the setter does **not** mutate `count` in the current scope; it\n  asks React to render again with a new value.\n",{"id":28,"difficulty":29,"q":30,"a":31},"async-state","medium","Why does state appear to be \"one render behind\"?","Because `count` is a **const captured by this render's closure**, not a live\nreference to a mutable box. Each render gets its own `count` constant frozen\nat the value it had when that render ran. Calling `setCount` schedules a\n*future* render with a new value — it cannot reach back and change the\n`count` you're currently looking at.\n\n```jsx\nfunction handleClick() {\n  console.log(count)   \u002F\u002F e.g. 0\n  setCount(count + 1)  \u002F\u002F schedules a render where count will be 1\n  console.log(count)   \u002F\u002F STILL 0 — same render, same frozen constant\n}\n```\n\nSo state isn't really \"behind\" — you're reading a snapshot. The new value\nbecomes visible only in the next render's function body. If you need the\nupdated value immediately after setting it, derive it locally\n(`const next = count + 1`) or read it in an effect that runs after the\nre-render.\n",{"id":33,"difficulty":29,"q":34,"a":35},"functional-update","When should you use a functional state update?","Use the functional form — `setCount(c => c + 1)` — whenever the next state is\n**derived from the previous state**, especially when several updates happen in\none event or across async boundaries. React passes the most up-to-date value\ninto your updater, so you never base a calculation on a stale snapshot.\n\n```jsx\n\u002F\u002F All three read the same stale `count`, so this adds 1, not 3\nsetCount(count + 1)\nsetCount(count + 1)\nsetCount(count + 1)\n\n\u002F\u002F Each updater receives the result of the previous one -> +3\nsetCount(c => c + 1)\nsetCount(c => c + 1)\nsetCount(c => c + 1)\n```\n\nRule of thumb: if the new value mentions the old value, prefer the function\nform. If you're setting an unrelated value (`setCount(0)`), the direct form\nis fine.\n",{"id":37,"difficulty":29,"q":38,"a":39},"lazy-init","What is lazy initial state?","If your initial value is expensive to compute, pass a **function** to\n`useState` instead of the value itself. React calls that function **only on\nthe first render** and ignores it afterwards. Passing the value directly would\nre-run the expensive computation on *every* render and then throw the result\naway.\n\n```jsx\n\u002F\u002F readFromLocalStorage() runs on every single render\nconst [items, setItems] = useState(readFromLocalStorage())\n\n\u002F\u002F runs once, on mount only\nconst [items, setItems] = useState(() => readFromLocalStorage())\n```\n\nWatch the distinction: `useState(expensive())` *calls* `expensive` every\nrender (its return value is the argument), whereas `useState(expensive)` \u002F\n`useState(() => expensive())` hands React the function to call once.\n",{"id":41,"difficulty":29,"q":42,"a":43},"object-state","How do you update an object in state?","Unlike `this.setState` in class components, the `useState` setter **replaces**\nthe value — it does not shallow-merge. To change one field of an object you\nmust spread the previous object yourself and override the field, returning a\n**new** object (mutating the existing one won't trigger a re-render because the\nreference is unchanged).\n\n```jsx\nconst [user, setUser] = useState({ name: 'Ada', age: 36 })\n\n\u002F\u002F new object, old fields preserved, name overridden\nsetUser(u => ({ ...u, name: 'Grace' }))\n\n\u002F\u002F mutates in place — same reference, React skips the re-render\nuser.name = 'Grace'\nsetUser(user)\n```\n\nFor deeply nested state this spreading gets verbose; that's often the signal\nto reach for `useReducer` or a state library.\n",{"id":45,"difficulty":46,"q":47,"a":48},"batching","hard","What is state batching?","Batching is React grouping multiple state updates into a **single re-render**\nfor performance, instead of re-rendering once per `setState` call. If you call\nthree setters in one click handler, React processes them together and renders\nonce.\n\n```jsx\nfunction handleClick() {\n  setA(1)\n  setB(2)\n  setC(3)\n  \u002F\u002F ONE re-render, not three\n}\n```\n\nBefore React 18, batching only happened inside React event handlers; updates\nin `setTimeout`, promises, or native event listeners each caused their own\nrender. **React 18's automatic batching** extends grouping to those async\ncontexts too. If you ever need to opt out and force a synchronous, separate\nrender, wrap the update in `flushSync` from `react-dom`.\n",{"id":50,"difficulty":29,"q":51,"a":52},"derived-state","Should you store computed\u002Fderived values in state?","Usually **no**. If a value can be calculated from existing props or state,\nderive it **during render** instead of duplicating it in `useState` — extra\nstate can drift out of sync and forces you to keep two things updated.\n\n```jsx\n\u002F\u002F redundant state that can desync\nconst [items, setItems] = useState([])\nconst [count, setCount] = useState(0)\n\n\u002F\u002F derive it\nconst [items, setItems] = useState([])\nconst count = items.length\n```\n\nOnly store something in state if it's genuinely independent input. \"You might\nnot need state\" is the React team's own guidance.\n",{"id":54,"difficulty":29,"q":55,"a":56},"lift-state-up","What does \"lifting state up\" mean?","When two components need to share or stay in sync over the same data, you move\nthe state to their **closest common parent** and pass it down as props plus a\nsetter callback. The parent becomes the single source of truth.\n\n```jsx\nfunction Parent() {\n  const [value, setValue] = useState('')\n  return (\n    \u003C>\n      \u003CInput value={value} onChange={setValue} \u002F>\n      \u003CPreview value={value} \u002F>\n    \u003C\u002F>\n  )\n}\n```\n\nIt's the standard fix for \"these siblings need the same data.\" When lifting gets\npainful across many levels, that's the signal to reach for Context or a store.\n",{"id":58,"difficulty":29,"q":59,"a":60},"usestate-vs-useref","When should you use useRef instead of useState?","Use `useState` for values that should **trigger a re-render** when they change.\nUse `useRef` for mutable values that should **persist across renders but NOT\ncause re-renders** — timer ids, previous values, DOM nodes.\n\n```jsx\nconst [count, setCount] = useState(0) \u002F\u002F UI depends on it -> re-render\nconst renders = useRef(0)             \u002F\u002F bookkeeping -> no re-render\nrenders.current++\n```\n\nChanging `ref.current` is invisible to React's render cycle. If the screen needs\nto reflect the value, it belongs in state; otherwise a ref avoids needless\nrenders.\n",{"id":62,"difficulty":46,"q":63,"a":64},"reset-state-key","How do you reset a component's state to its initial values?","The cleanest way is to change the component's **`key`**. React treats a new key\nas a brand-new component, unmounting the old instance (discarding its state) and\nmounting a fresh one — no manual reset code.\n\n```jsx\n\u003CProfile key={userId} userId={userId} \u002F>\n\u002F\u002F when userId changes, Profile remounts with fresh state\n```\n\nAlternatives are manually calling setters back to initial values, but `key` is\nidiomatic for \"start this subtree over.\" Avoid resetting state inside an effect\nby watching a prop — the `key` approach is simpler and bug-free.\n",{"id":66,"difficulty":46,"q":67,"a":68},"store-function-state","How do you store a function in state?","Because the `useState` setter treats a **function argument as an updater**, you\nmust wrap a function you want to *store* in another function — otherwise React\ncalls it instead of saving it.\n\n```jsx\n\u002F\u002F React invokes handleClick to compute the next state\nconst [fn, setFn] = useState(handleClick)\nsetFn(handleClick)\n\n\u002F\u002F wrap it so it's stored, not called\nconst [fn, setFn] = useState(() => handleClick)\nsetFn(() => handleClick)\n```\n\nThe same rule applies to lazy initialization. Storing functions in state is rare\n— usually a ref or just defining the function in render is cleaner.\n",{"id":70,"difficulty":14,"q":71,"a":72},"array-state-add","How do you add and remove items in array state?","Treat the array as **immutable** — never `push`\u002F`splice` the existing array\n(same reference -> no re-render). Build a new array with spread or `filter`.\n\n```jsx\n\u002F\u002F add\nsetItems(prev => [...prev, newItem])\n\u002F\u002F remove by id\nsetItems(prev => prev.filter(it => it.id !== id))\n\u002F\u002F insert at index\nsetItems(prev => [...prev.slice(0, i), newItem, ...prev.slice(i)])\n```\n\nUsing the functional updater (`prev =>`) keeps you correct when several updates\nbatch together.\n",{"id":74,"difficulty":29,"q":75,"a":76},"array-state-update","How do you update one object inside an array in state?","Map over the array, returning a **new object** for the matching item and the\noriginals for the rest. Mutating the found object in place won't re-render and\ncan corrupt previous renders.\n\n```jsx\nsetUsers(prev =>\n  prev.map(u => u.id === id ? { ...u, name: 'Ada' } : u)\n)\n```\n\nThe rule: new array **and** new object for whatever you change. For deeply\nnested updates this gets verbose — a signal to use `useReducer` or Immer.\n",{"id":78,"difficulty":46,"q":79,"a":80},"usestate-vs-usereducer","When should you choose useReducer over useState?","Reach for `useReducer` when state is **complex** (multiple sub-values that change\ntogether), when the **next state depends on intricate logic**, or when you want\nto **centralize update logic** in one tested function instead of scattering\nsetters.\n\n```jsx\nconst [state, dispatch] = useReducer(reducer, initial)\ndispatch({ type: 'increment', by: 2 })\n```\n\n`useState` is best for simple, independent values. A heuristic: if you find\nyourself calling several setters together or your setter logic is branchy, a\nreducer makes intent clearer and easier to test.\n",{"id":82,"difficulty":14,"q":83,"a":84},"controlled-input","How do you build a controlled input with useState?","A controlled input gets its `value` from state and updates state on every\nkeystroke via `onChange`, making React the single source of truth.\n\n```jsx\nconst [text, setText] = useState('')\n\u003Cinput value={text} onChange={e => setText(e.target.value)} \u002F>\n```\n\nForgetting `onChange` while setting `value` makes the field **read-only** (React\nwarns). The benefit is you can validate, format, or react to every change; the\ncost is a re-render per keystroke (rarely a problem).\n",{"id":86,"difficulty":29,"q":87,"a":88},"controlled-vs-uncontrolled","What is the difference between controlled and uncontrolled components?","- **Controlled** — React state holds the value (`value` + `onChange`). Predictable\n  and easy to validate, but re-renders on each change.\n- **Uncontrolled** — the DOM holds the value; you read it via a `ref` when needed\n  (`defaultValue` for the initial value).\n\n```jsx\n\u002F\u002F uncontrolled\nconst ref = useRef()\n\u003Cinput defaultValue=\"hi\" ref={ref} \u002F>\n\u002F\u002F read ref.current.value on submit\n```\n\nControlled is the default recommendation; uncontrolled suits simple forms,\nfile inputs, or integrating non-React widgets.\n",{"id":90,"difficulty":29,"q":91,"a":92},"multiple-vs-single-object","Should you use multiple state variables or one state object?","Prefer **multiple `useState` calls** for values that change independently — it's\nsimpler and you don't have to spread-merge on every update. Group into one object\nonly when fields genuinely change **together**.\n\n```jsx\n\u002F\u002F independent values\nconst [name, setName] = useState('')\nconst [age, setAge] = useState(0)\n\n\u002F\u002F grouping requires manual merge (no auto-merge like class setState)\nsetForm(prev => ({ ...prev, name: 'Ada' }))\n```\n\nRemember the `useState` setter **replaces**, it doesn't merge — so an object of\nstate means spreading the rest every time.\n",{"id":94,"difficulty":46,"q":95,"a":96},"nested-object-update","How do you update deeply nested state immutably?","Spread at **every** level you change, all the way down — only the touched\nbranches get new references.\n\n```jsx\nsetUser(prev => ({\n  ...prev,\n  address: { ...prev.address, city: 'Paris' },\n}))\n```\n\nThis is error-prone and verbose for deep trees. Options: restructure to flatter\nstate, switch to `useReducer`, or use **Immer** (`produce`) which lets you\n\"mutate\" a draft and produces the immutable update for you.\n",{"id":98,"difficulty":29,"q":99,"a":100},"avoid-redundant-state","What is redundant state and why avoid it?","Redundant state is data you keep in `useState` that's already derivable from\nother state or props. It invites bugs because you must remember to update it\neverywhere, and the copies can disagree.\n\n```jsx\n\u002F\u002F fullName must be kept in sync manually\nconst [fullName, setFullName] = useState('')\n\u002F\u002F derive it\nconst fullName = `${first} ${last}`\n```\n\nKeep state **minimal and orthogonal** — the smallest set of independent values\nfrom which everything else is computed during render.\n",{"id":102,"difficulty":14,"q":103,"a":104},"toggle-boolean","How do you toggle a boolean in state?","Use the functional updater so you always flip the **latest** value, which matters\nif toggles can batch.\n\n```jsx\nconst [open, setOpen] = useState(false)\nconst toggle = () => setOpen(o => !o)\n```\n\nAvoid `setOpen(!open)` in code paths that may run multiple times in one event —\nit reads a possibly stale `open`. The functional form is always safe.\n",{"id":106,"difficulty":46,"q":107,"a":108},"prev-in-async","How do you read the latest state inside an async callback?","A callback captures the state value from the render it was created in, so after\nan `await` it may be **stale**. To act on the latest value, use the functional\nupdater (which receives the current value) or store it in a ref.\n\n```jsx\nasync function save() {\n  await delay(1000)\n  \u002F\u002F `count` is whatever it was when save() was created\n  \u002F\u002F read the latest via the updater\n  setCount(latest => { send(latest); return latest })\n}\n```\n\nCleaner still: pass the needed value as an argument, or keep a `useRef` mirror of\nthe state for \"read latest\" access without triggering renders.\n",{"id":110,"difficulty":46,"q":111,"a":112},"set-bailout","Does setting state to the same value cause a re-render?","If you set state to a value that's **`Object.is`-equal** to the current one,\nReact **bails out** and skips re-rendering that component (it may still re-run\nthe component once to check, then stop).\n\n```jsx\nconst [n, setN] = useState(0)\nsetN(0) \u002F\u002F same value -> React bails out, no committed re-render\n```\n\nThe catch: this is **reference** equality. `setItems([])` with a *new* empty\narray is a different reference, so it **does** re-render even though the contents\nlook identical. Don't create fresh objects\u002Farrays for \"no change.\"\n",{"id":114,"difficulty":14,"q":115,"a":116},"state-vs-props","What is the difference between state and props?","- **State** is data a component **owns and can change** over time via its setter.\n- **Props** are data **passed in from a parent**; the child treats them as\n  **read-only**.\n\n```jsx\nfunction Counter({ step }) {        \u002F\u002F step is a prop (read-only)\n  const [count, setCount] = useState(0) \u002F\u002F count is state (owned)\n  return \u003Cbutton onClick={() => setCount(c => c + step)}>{count}\u003C\u002Fbutton>\n}\n```\n\nA child never mutates props; to change parent data it calls a callback prop. One\ncomponent's state is often another's props (passed down).\n",{"id":118,"difficulty":29,"q":119,"a":120},"rules-of-hooks","Why must useState be called at the top level, not in conditions?","React identifies each hook by its **call order**, not a name. Calling `useState`\ninside a condition, loop, or after an early return changes that order between\nrenders, so React mismatches state to the wrong hook.\n\n```jsx\n\u002F\u002F breaks hook ordering\nif (loggedIn) {\n  const [name, setName] = useState('')\n}\n\u002F\u002F always call unconditionally; branch on the value\nconst [name, setName] = useState('')\nif (loggedIn) { \u002F* use name *\u002F }\n```\n\nAlways call hooks at the top level of the component, in the same order every\nrender — the `eslint-plugin-react-hooks` rule enforces this.\n",{"id":122,"difficulty":29,"q":123,"a":124},"state-no-rerender","When does updating state not trigger a re-render?","Two common cases: (1) you **mutated** the existing object\u002Farray and passed the\nsame reference, so React sees no change; or (2) you set a primitive to the\n**same value** (React bails out via `Object.is`).\n\n```jsx\n\u002F\u002F mutate + same reference -> no re-render\nuser.name = 'Ada'\nsetUser(user)\n\u002F\u002F new reference\nsetUser({ ...user, name: 'Ada' })\n```\n\nThe fix is always to produce a **new reference** for changed objects\u002Farrays. If\nthe UI \"isn't updating,\" this mutation trap is the first thing to check.\n",{"id":126,"difficulty":46,"q":127,"a":128},"set-during-render","Can you call a state setter during render?","Generally you should not — setting state in the render body unconditionally\ncauses an **infinite loop**. React *does* support a narrow pattern: calling a\nsetter **conditionally during render** to adjust state based on a prop change,\nwhich it handles without an extra paint.\n\n```jsx\n\u002F\u002F rare, allowed: derive on prop change without an effect\nconst [prevId, setPrevId] = useState(id)\nif (id !== prevId) {\n  setPrevId(id)\n  setSelection(null) \u002F\u002F reset when id changes, no effect needed\n}\n```\n\nMost of the time you don't need this — prefer deriving values or the `key` reset\ntrick. Never call a setter unconditionally in render.\n",{"id":130,"difficulty":29,"q":131,"a":132},"setstate-loop","What causes an infinite re-render loop with useState?","Calling a setter **unconditionally during render**, or inside an effect whose\ndependencies you keep changing, makes React render -> set -> render forever.\n\n```jsx\n\u002F\u002F sets state every render -> infinite loop\nconst [n, setN] = useState(0)\nsetN(n + 1)\n\n\u002F\u002F effect with a new object dep each render\nuseEffect(() => setData(load()), [{}])\n```\n\nFixes: only set state in **event handlers** or **effects with stable deps**,\nderive values instead of storing them, and avoid fresh object\u002Farray literals in\ndependency arrays.\n",{"id":134,"difficulty":46,"q":135,"a":136},"state-from-props","Why doesn't state update when the prop used to initialize it changes?","The `useState` initializer is only read on the **first render**. Passing a prop\nas the initial value captures it once; later changes to the prop don't flow into\nthe state.\n\n```jsx\nfunction Field({ initial }) {\n  const [value, setValue] = useState(initial) \u002F\u002F only the first `initial` is used\n  \u002F\u002F later `initial` changes are ignored\n}\n```\n\nIf you truly need to reset when the prop changes, use the **`key`** prop to\nremount, or the conditional set-during-render pattern. Often the better answer is\nto not copy the prop into state at all.\n",{"id":138,"difficulty":29,"q":139,"a":140},"expensive-derived","How do you cache an expensive derived value without storing it in state?","Use `useMemo` — it recomputes the value only when its dependencies change, so you\nget the benefit of a cached derivation **without** the desync risk of putting it\nin state.\n\n```jsx\nconst sorted = useMemo(\n  () => [...items].sort(compare),\n  [items]\n)\n```\n\nThis keeps `items` as the single source of truth while avoiding re-sorting on\nevery keystroke. Don't reach for `useMemo` until the computation is actually\nexpensive — needless memoization adds its own overhead.\n",{"id":142,"difficulty":29,"q":143,"a":144},"state-colocation","Where should state live in a React component tree?","Keep state as **close as possible** to where it's used (colocation), and lift it\nonly as high as the nearest common ancestor that needs to share it. Over-lifting\nstate to the top causes unnecessary re-renders and prop drilling.\n\n```jsx\n\u002F\u002F a modal's \"open\" state belongs in the component that owns the modal,\n\u002F\u002F not in the app root\nfunction Toolbar() {\n  const [open, setOpen] = useState(false)\n  \u002F\u002F ...\n}\n```\n\nColocated state means fewer renders and simpler components; global\u002Fapp state\nshould be reserved for genuinely shared data.\n",{"id":146,"difficulty":29,"q":147,"a":148},"form-generic-handler","How do you manage many form fields with one state object?","Hold the fields in one object and use a generic change handler keyed by the\ninput's `name`, spreading the previous object to preserve the other fields.\n\n```jsx\nconst [form, setForm] = useState({ name: '', email: '' })\nconst onChange = e =>\n  setForm(prev => ({ ...prev, [e.target.name]: e.target.value }))\n\n\u003Cinput name=\"email\" value={form.email} onChange={onChange} \u002F>\n```\n\nThe computed key `[e.target.name]` updates just one field. For large\u002Fvalidated\nforms, a form library or `useReducer` scales better than hand-rolling this.\n",{"id":150,"difficulty":29,"q":151,"a":152},"no-setstate-callback","Is there a setState callback like in class components?","No. The class `this.setState(value, callback)` second argument doesn't exist for\nthe `useState` setter. To run code **after** a state update commits, use a\n`useEffect` that depends on that state.\n\n```jsx\nconst [count, setCount] = useState(0)\nuseEffect(() => {\n  \u002F\u002F runs after the render caused by count changing\n  analytics.track(count)\n}, [count])\n```\n\nThis is the hooks way to \"do X after state changes\" — react to the new value in\nan effect rather than passing a callback to the setter.\n",{"id":154,"difficulty":14,"q":155,"a":156},"number-input","How do you handle number inputs with useState?","An `\u003Cinput>`'s value is always a **string**, so convert it when you need a\nnumber, and decide how to handle empty\u002Finvalid input.\n\n```jsx\nconst [age, setAge] = useState('')\n\u003Cinput\n  type=\"number\"\n  value={age}\n  onChange={e => setAge(e.target.value)} \u002F\u002F keep the raw string in state\n\u002F>\nconst ageNum = age === '' ? 0 : Number(age) \u002F\u002F parse where you use it\n```\n\nStoring the raw string avoids fighting the input (e.g. a partially typed `-` or\n`.`), and you parse to a number only at the point of use.\n",{"id":158,"difficulty":46,"q":159,"a":160},"batched-puzzle","What does calling the same setter three times with the value form produce?","```jsx\nconst [count, setCount] = useState(0)\nfunction handle() {\n  setCount(count + 1)\n  setCount(count + 1)\n  setCount(count + 1)\n} \u002F\u002F after one click, count is 1 — not 3\n```\n\nAll three read the **same** `count` (0) from this render's closure, each\ncomputing `1`, and batching collapses them to a single update of `1`. Use the\nfunctional form to actually add 3:\n\n```jsx\nsetCount(c => c + 1) \u002F\u002F ×3 -> each receives the previous result -> 3\n```\n\nThis puzzle tests whether you understand closures-over-state plus batching.\n",null,{"description":11},"React useState interview questions — state updates, batching, functional updates, lazy initialization and why state seems one render behind.","react\u002Fhooks\u002Fusestate","useState","Hooks","hooks","2026-06-17","ecZdz3Hz9vchxC3tS5HAVYkPMt3Vp8u1wGhzVLUHQ4Q",[171,172],{"subtopic":165,"path":21,"order":20},{"subtopic":173,"path":174,"order":12},"useEffect","\u002Freact\u002Fhooks\u002Fuseeffect",{"path":176,"title":177},"\u002Fblog\u002Freact-usestate-hook-complete-guide","React useState Hook — A Complete Guide with Examples",1781808676696]