[{"data":1,"prerenderedAt":338},["ShallowReactive",2],{"topic-react-state-and-data-flow":3},{"framework":4,"topic":15,"subtopics":24},{"id":5,"description":6,"extension":7,"icon":8,"meta":9,"name":10,"order":11,"slug":8,"stem":12,"tier":13,"__hash__":14},"frameworks\u002Fframeworks\u002Freact.yml","React interview questions on hooks, components, state and rendering — the most-requested front-end framework in technical interviews.","yml","react",{},"React",2,"frameworks\u002Freact",1,"RA6wemU0xFHrA1ZKCABP1J7MireA3Bt_FCJMOuMgsm0",{"id":16,"description":17,"extension":7,"frameworkSlug":8,"meta":18,"name":19,"order":20,"slug":21,"stem":22,"__hash__":23},"topics\u002Ftopics\u002Freact-state-and-data-flow.yml","Lifting state, the Context API, controlled vs. uncontrolled components, and solutions to prop drilling — how data moves through a React application.",{},"State and Data Flow",3,"state-and-data-flow","topics\u002Freact-state-and-data-flow","rig9Wq4Cttex5N-dzRNa_G5der7uowUIHS6BONtnkbw",[25,115,192,265],{"id":26,"title":27,"body":28,"description":32,"difficulty":34,"extension":35,"framework":10,"frameworkSlug":8,"meta":36,"navigation":38,"order":13,"path":39,"questions":40,"questionsCount":107,"related":108,"seo":109,"seoDescription":110,"stem":111,"subtopic":112,"topic":19,"topicSlug":21,"updated":113,"__hash__":114},"qa\u002Freact\u002Fstate-and-data-flow\u002Flifting-state.md","Lifting State",{"type":29,"value":30,"toc":31},"minimark",[],{"title":32,"searchDepth":11,"depth":11,"links":33},"",[],"easy","md",{"subtopicSlug":37},"lifting-state",true,"\u002Freact\u002Fstate-and-data-flow\u002Flifting-state",[41,45,49,53,57,62,66,70,74,78,82,86,90,94,98,102],{"id":42,"difficulty":34,"q":43,"a":44},"lifting-state-what","What does \"lifting state up\" mean in React?","**Lifting state up** means moving shared state to the **lowest common\nancestor** of the components that need it. The ancestor owns the state\nand passes both the value and a setter callback down as props, so siblings\ncan read the same data and trigger updates through a common parent.\n\n```jsx\nfunction Parent() {\n  const [value, setValue] = useState('')\n\n  return (\n    \u003C>\n      \u003CInput value={value} onChange={setValue} \u002F>\n      \u003CPreview value={value} \u002F>\n    \u003C\u002F>\n  )\n}\n\n\u002F\u002F Input writes, Preview reads — state lives in Parent\n```\n\n**Rule of thumb:** If two components need to stay in sync, lift their\nshared state to the closest ancestor that contains both of them.\n",{"id":46,"difficulty":34,"q":47,"a":48},"lifting-state-why","Why is lifting state up necessary instead of each component keeping its own copy?","React enforces **one-way data flow** — a child cannot directly read or\nwrite a sibling's state. If two components each hold their own copy of\nthe same value, those copies can diverge and the UI becomes inconsistent.\n\n```jsx\n\u002F\u002F ❌ Two independent copies — can get out of sync\nfunction A() { const [x, setX] = useState(0); ... }\nfunction B() { const [x, setX] = useState(0); ... }\n\n\u002F\u002F ✅ One source of truth in the common parent\nfunction Parent() {\n  const [x, setX] = useState(0)\n  return \u003C>\u003CA x={x} onChange={setX} \u002F>\u003CB x={x} \u002F>\u003C\u002F>\n}\n```\n\nA single source of truth makes behaviour predictable: any change flows\ndown from the owner and every consumer automatically re-renders with\nthe latest value.\n\n**Rule of thumb:** If you ever copy state from props into another\n`useState`, you almost certainly have a sync problem waiting to happen.\n",{"id":50,"difficulty":34,"q":51,"a":52},"lifting-state-callback","How does a child component communicate a change back to its parent?","The parent passes a **callback prop** (e.g. `onChange`, `onSubmit`) to\nthe child. When the user interacts, the child calls that callback with\nthe new value. The parent's setter updates state, which flows back down.\n\n```jsx\nfunction Parent() {\n  const [qty, setQty] = useState(1)\n  return \u003CQuantityInput value={qty} onChange={setQty} \u002F>\n}\n\nfunction QuantityInput({ value, onChange }) {\n  return (\n    \u003Cinput\n      type=\"number\"\n      value={value}\n      onChange={e => onChange(Number(e.target.value))}\n    \u002F>\n  )\n}\n```\n\nThe child owns zero state here — it is a **controlled** component driven\nentirely by props.\n\n**Rule of thumb:** Name callbacks `onX` in the parent and `handleX`\ninside the child to keep the intent clear.\n",{"id":54,"difficulty":34,"q":55,"a":56},"lifting-state-siblings","Two sibling components need to share data. Where should the state live?","In their **closest common ancestor**. That ancestor becomes the single\nsource of truth and distributes both the value and update callbacks.\n\n```jsx\n\u002F\u002F Siblings: SearchBar and ResultsList need the same query string\nfunction SearchPage() {\n  const [query, setQuery] = useState('')\n\n  return (\n    \u003Cdiv>\n      \u003CSearchBar query={query} onSearch={setQuery} \u002F>\n      \u003CResultsList query={query} \u002F>\n    \u003C\u002Fdiv>\n  )\n}\n```\n\nAvoid the temptation to let one sibling own the state and pass it\nsideways — React has no sibling-to-sibling channel.\n\n**Rule of thumb:** Siblings communicate via a shared parent, never\ndirectly.\n",{"id":58,"difficulty":59,"q":60,"a":61},"lifting-state-too-high","medium","What goes wrong if you lift state higher than necessary?","Every component that receives the state as a prop will re-render when\nthat state changes — including ones that don't use it but happen to\nsit between the owner and the consumer. This causes **unnecessary\nre-renders** and can hurt performance in large trees.\n\n```jsx\n\u002F\u002F If `query` lives in App, every child of App re-renders on each\n\u002F\u002F keystroke — even Header, Sidebar, Footer that don't care about query\nfunction App() {\n  const [query, setQuery] = useState('')\n  return (\n    \u003C>\n      \u003CHeader \u002F>       {\u002F* re-renders needlessly *\u002F}\n      \u003CSidebar \u002F>      {\u002F* re-renders needlessly *\u002F}\n      \u003CSearchPage query={query} onSearch={setQuery} \u002F>\n    \u003C\u002F>\n  )\n}\n```\n\nKeep state as **low** in the tree as possible while still being shared\nwhere needed.\n\n**Rule of thumb:** Lift only as high as required; don't promote state\npre-emptively \"in case\" something else needs it.\n",{"id":63,"difficulty":59,"q":64,"a":65},"lifting-state-vs-context","When should you lift state vs. reach for Context or a global store?","| Scenario | Approach |\n|---|---|\n| 1–2 levels of passing, few consumers | Lift state (props) |\n| Deeply nested tree, many consumers, changes infrequently | Context |\n| Frequently updated, many subscribers, complex logic | External store (Redux, Zustand) |\n\nLifted state is the **simplest** solution and should be the default.\nContext adds an implicit dependency and can cause broad re-renders.\nA global store adds a dependency and operational complexity.\n\n```jsx\n\u002F\u002F Fine with lifting (shallow):\n\u003CPage>\u003CFilterBar \u002F>\u003CTable \u002F>\u003C\u002FPage>\n\n\u002F\u002F Consider Context (deeply nested):\n\u003CApp>\u003CLayout>\u003CSidebar>\u003CDeepWidget \u002F>\u003C\u002FSidebar>\u003C\u002FLayout>\u003C\u002FApp>\n```\n\n**Rule of thumb:** Start with lifting. Reach for Context only when prop\ndrilling becomes painful; reach for a store only when Context causes\nperformance problems.\n",{"id":67,"difficulty":34,"q":68,"a":69},"lifting-state-controlled","What is the relationship between lifting state and controlled components?","When you lift state into a parent and pass `value` + `onChange` to an\ninput, that input becomes a **controlled component** — the parent's\nstate is the single source of truth for the field's current value.\n\n```jsx\n\u002F\u002F Parent owns the state → input is controlled\nfunction Form() {\n  const [email, setEmail] = useState('')\n  return (\n    \u003Cinput\n      value={email}                         \u002F\u002F controlled\n      onChange={e => setEmail(e.target.value)}\n    \u002F>\n  )\n}\n```\n\nWithout lifting, each input would manage its own uncontrolled state\n(the DOM), making it harder for the parent to read or validate values.\n\n**Rule of thumb:** Forms almost always need lifted, controlled state so\nthe parent can validate and submit the combined field values.\n",{"id":71,"difficulty":59,"q":72,"a":73},"lifting-state-derived","What is derived state, and how does it relate to lifting?","**Derived state** is any value you can compute from existing state or\nprops. It should **not** be duplicated in a second `useState` — compute\nit inline during render instead.\n\n```jsx\n\u002F\u002F ❌ Redundant state — fullName can diverge\nconst [firstName, setFirstName] = useState('')\nconst [lastName, setLastName] = useState('')\nconst [fullName, setFullName] = useState('')   \u002F\u002F duplicated!\n\n\u002F\u002F ✅ Derive it — always in sync, zero extra state\nconst fullName = `${firstName} ${lastName}`\n```\n\nLifting state and avoiding derived copies are two sides of the same\ncoin: both enforce a **single source of truth**.\n\n**Rule of thumb:** If a value can be computed from existing state, don't\nstore it separately — just compute it.\n",{"id":75,"difficulty":59,"q":76,"a":77},"lifting-state-performance","How can you prevent child re-renders caused by callback props passed from a parent?","Wrap the callback in `useCallback` so the function reference is stable\nbetween renders. Pair it with `React.memo` on the child to skip\nre-renders when neither value nor callback changed.\n\n```jsx\nfunction Parent() {\n  const [count, setCount] = useState(0)\n\n  const handleChange = useCallback((val) => {\n    setCount(val)\n  }, [])                  \u002F\u002F stable reference\n\n  return \u003CExpensiveChild onChange={handleChange} count={count} \u002F>\n}\n\nconst ExpensiveChild = React.memo(({ count, onChange }) => {\n  \u002F\u002F only re-renders when count or onChange actually changes\n  return \u003Cinput value={count} onChange={e => onChange(Number(e.target.value))} \u002F>\n})\n```\n\nWithout `useCallback`, a new function is created every render, breaking\n`React.memo`'s shallow equality check.\n\n**Rule of thumb:** `useCallback` is most valuable when the callback is\npassed to a memoized child — otherwise it's premature optimisation.\n",{"id":79,"difficulty":59,"q":80,"a":81},"lifting-state-multiple","When multiple pieces of related state need to be lifted, should they be separate useState calls or one object?","Group them in **one object** (or `useReducer`) when they change together\nor are conceptually coupled. Keep them separate when they change\nindependently.\n\n```jsx\n\u002F\u002F ✅ Coupled — lift as one object\nconst [position, setPosition] = useState({ x: 0, y: 0 })\n\u002F\u002F Update: setPosition(prev => ({ ...prev, x: newX }))\n\n\u002F\u002F ✅ Independent — separate calls\nconst [isOpen, setIsOpen] = useState(false)\nconst [query, setQuery]   = useState('')\n```\n\nGrouping reduces the number of props you thread through the tree;\nkeeping them separate avoids unnecessary object spread on every update.\n\n**Rule of thumb:** If you always update both values at the same time,\ngroup them; if you update them independently, keep them separate.\n",{"id":83,"difficulty":59,"q":84,"a":85},"lifting-state-initialiser","How do you initialise lifted state from a prop only once without re-syncing on every render?","Pass the initial value as the `useState` initialiser argument. React\nonly evaluates it on the **first render** — subsequent prop changes are\nintentionally ignored because the state is now owned by the parent.\n\n```jsx\n\u002F\u002F ❌ Anti-pattern: syncing prop to state on every render\nfunction Child({ initialCount }) {\n  const [count, setCount] = useState(initialCount)\n  useEffect(() => { setCount(initialCount) }, [initialCount])\n  \u002F\u002F now state and prop fight for ownership\n}\n\n\u002F\u002F ✅ Use initialValue convention — document that updates won't flow down\nfunction Counter({ initialCount }) {\n  const [count, setCount] = useState(initialCount)  \u002F\u002F first render only\n  return \u003Cbutton onClick={() => setCount(c => c + 1)}>{count}\u003C\u002Fbutton>\n}\n```\n\nIf ongoing sync is required, the parent should own the state and pass a\ncontrolled value + callback instead.\n\n**Rule of thumb:** Prefix props that seed state only once with\n`initial` (`initialCount`, `initialValue`) to signal they're not\nkept in sync.\n",{"id":87,"difficulty":34,"q":88,"a":89},"lifting-state-handler-naming","What naming convention is commonly used for event-handler props when lifting state?","Use `onX` for props that accept a callback and `handleX` for the\nfunction itself — mirroring React's own `onClick`, `onChange`, etc.\n\n```jsx\n\u002F\u002F Parent — owns state, names the prop onSearch\nfunction SearchPage() {\n  const [query, setQuery] = useState('')\n  function handleSearch(q) { setQuery(q) }\n\n  return \u003CSearchBar onSearch={handleSearch} \u002F>\n}\n\n\u002F\u002F Child — receives the prop, calls it when the user acts\nfunction SearchBar({ onSearch }) {\n  return \u003Cinput onChange={e => onSearch(e.target.value)} \u002F>\n}\n```\n\nConsistent naming makes it immediately obvious at the call site which\nprop triggers parent behaviour.\n\n**Rule of thumb:** `on` prefix = prop the caller provides;\n`handle` prefix = the local function that implements it.\n",{"id":91,"difficulty":34,"q":92,"a":93},"lifting-state-unidirectional","What is \"unidirectional data flow\" and why does React enforce it?","**Unidirectional data flow** means data travels in one direction only:\n**down** the tree via props. A child can signal a change (via callback),\nbut the parent decides whether and how state updates, then the new value\nflows back down.\n\n```\nParent state\n     ↓ props\n  Child A     Child B\n     ↑ callback (event)\n```\n\nThis makes the state transitions explicit, predictable, and easy to\ndebug — you always know where a piece of data lives and who can change\nit.\n\n**Rule of thumb:** If you find yourself needing to pass data *upward*\nwithout a callback, that's a sign the state should live higher or in\na shared store.\n",{"id":95,"difficulty":59,"q":96,"a":97},"lifting-state-anti-pattern-sync","Why is copying parent state into child state considered an anti-pattern?","When you copy a prop into `useState`, you create two sources of truth.\nIf the parent updates the prop, the child's copy stays stale unless you\nadd a `useEffect` to sync — which introduces complexity and can cause\none-render lag bugs.\n\n```jsx\n\u002F\u002F ❌ Derived state anti-pattern\nfunction Child({ value }) {\n  const [localValue, setLocalValue] = useState(value)\n  \u002F\u002F If parent changes `value`, localValue is now stale\n  useEffect(() => setLocalValue(value), [value]) \u002F\u002F band-aid\n}\n\n\u002F\u002F ✅ Just use the prop directly\nfunction Child({ value, onChange }) {\n  return \u003Cinput value={value} onChange={e => onChange(e.target.value)} \u002F>\n}\n```\n\nThe key insight: if a component should be driven by the parent, make\nit **fully controlled** — no local copy.\n\n**Rule of thumb:** Before writing `useState(someProp)`, ask whether the\nchild really needs to own that state. Usually the answer is no.\n",{"id":99,"difficulty":59,"q":100,"a":101},"lifting-state-form-submit","How does lifting state enable a parent to collect and submit form field values?","With lifted state, the parent holds every field value and can read them\nall in the submit handler without querying the DOM.\n\n```jsx\nfunction SignupForm() {\n  const [form, setForm] = useState({ name: '', email: '' })\n\n  function handleChange(field, value) {\n    setForm(prev => ({ ...prev, [field]: value }))\n  }\n\n  function handleSubmit(e) {\n    e.preventDefault()\n    api.signup(form)   \u002F\u002F all values available here\n  }\n\n  return (\n    \u003Cform onSubmit={handleSubmit}>\n      \u003CTextInput label=\"Name\"  value={form.name}  onChange={v => handleChange('name', v)} \u002F>\n      \u003CTextInput label=\"Email\" value={form.email} onChange={v => handleChange('email', v)} \u002F>\n      \u003Cbutton type=\"submit\">Sign up\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n```\n\n**Rule of thumb:** Lift all form fields into the parent that owns the\nsubmit action so validation and submission see a consistent snapshot.\n",{"id":103,"difficulty":104,"q":105,"a":106},"lifting-state-list-items","hard","How do you handle lifted state for a dynamic list where each item has its own editable fields?","Store the list in the parent as an array of objects. Pass each item and\nan `onChange` callback that identifies the item by index or `id`.\n\n```jsx\nfunction TodoList() {\n  const [todos, setTodos] = useState([\n    { id: 1, text: 'Buy milk', done: false },\n    { id: 2, text: 'Walk dog', done: false },\n  ])\n\n  function handleToggle(id) {\n    setTodos(prev =>\n      prev.map(t => t.id === id ? { ...t, done: !t.done } : t)\n    )\n  }\n\n  return todos.map(todo => (\n    \u003CTodoItem key={todo.id} todo={todo} onToggle={handleToggle} \u002F>\n  ))\n}\n\nfunction TodoItem({ todo, onToggle }) {\n  return (\n    \u003Clabel>\n      \u003Cinput type=\"checkbox\" checked={todo.done}\n             onChange={() => onToggle(todo.id)} \u002F>\n      {todo.text}\n    \u003C\u002Flabel>\n  )\n}\n```\n\nThe parent is the single source of truth for the entire list; each\nchild is a controlled component.\n\n**Rule of thumb:** Always identify list items by a stable `id` (not\nindex) when items can be added, removed, or reordered.\n",16,null,{"description":32},"React lifting state interview questions — single source of truth, callback props, sibling communication, when to lift vs. use a store.","react\u002Fstate-and-data-flow\u002Flifting-state","Lifting State Up","2026-06-24","crdExT6WcsvjkdZN2V3ZRKAnaBpWm4wpjIfDlOEHUss",{"id":116,"title":117,"body":118,"description":32,"difficulty":59,"extension":35,"framework":10,"frameworkSlug":8,"meta":122,"navigation":38,"order":11,"path":124,"questions":125,"questionsCount":186,"related":108,"seo":187,"seoDescription":188,"stem":189,"subtopic":190,"topic":19,"topicSlug":21,"updated":113,"__hash__":191},"qa\u002Freact\u002Fstate-and-data-flow\u002Fcontext-api.md","Context Api",{"type":29,"value":119,"toc":120},[],{"title":32,"searchDepth":11,"depth":11,"links":121},[],{"subtopicSlug":123},"context-api","\u002Freact\u002Fstate-and-data-flow\u002Fcontext-api",[126,130,134,138,142,146,150,154,158,162,166,170,174,178,182],{"id":127,"difficulty":34,"q":128,"a":129},"context-what","What problem does the React Context API solve?","Context provides a way to pass data through the component tree **without\nthreading props through every intermediate level** — solving what is\nknown as **prop drilling**.\n\n```jsx\n\u002F\u002F Without Context — every layer must pass `theme` down\n\u003CApp theme=\"dark\">\n  \u003CLayout theme=\"dark\">\n    \u003CSidebar theme=\"dark\">\n      \u003CButton theme=\"dark\" \u002F>\n    \u003C\u002FSidebar>\n  \u003C\u002FLayout>\n\u003C\u002FApp>\n\n\u002F\u002F With Context — Button reads theme directly\nconst ThemeContext = createContext('light')\n\nfunction App() {\n  return (\n    \u003CThemeContext.Provider value=\"dark\">\n      \u003CLayout \u002F>         {\u002F* no theme prop needed *\u002F}\n    \u003C\u002FThemeContext.Provider>\n  )\n}\n\nfunction Button() {\n  const theme = useContext(ThemeContext)   \u002F\u002F reads directly\n  return \u003Cbutton className={theme}>Click\u003C\u002Fbutton>\n}\n```\n\n**Rule of thumb:** Use Context for truly global or widely shared data\n(theme, locale, auth user). Don't reach for it to avoid one or two\nlevels of prop passing.\n",{"id":131,"difficulty":34,"q":132,"a":133},"context-create","What does createContext do and what does its argument represent?","`createContext(defaultValue)` creates a Context object. The\n**default value** is used only when a component reads the context\n*without* a matching `Provider` above it in the tree — it is not the\ninitial value of the Provider.\n\n```jsx\n\u002F\u002F Default value is 'light' — used only outside any Provider\nconst ThemeContext = createContext('light')\n\nfunction App() {\n  return (\n    \u003CThemeContext.Provider value=\"dark\">\n      \u003CChild \u002F>   {\u002F* reads 'dark' *\u002F}\n    \u003C\u002FThemeContext.Provider>\n  )\n}\n\nfunction Orphan() {\n  \u002F\u002F No Provider above → reads the default 'light'\n  const theme = useContext(ThemeContext)\n  return \u003Cdiv>{theme}\u003C\u002Fdiv>\n}\n```\n\n**Rule of thumb:** Set the default value to something that makes the\ncomponent usable in isolation (e.g. in tests or Storybook) without\nwrapping it in a Provider.\n",{"id":135,"difficulty":34,"q":136,"a":137},"context-use-context","How do you consume a context value inside a function component?","Call `useContext(MyContext)` at the top level of the component. It\nreturns the current context value provided by the nearest matching\n`Provider` up the tree.\n\n```jsx\nimport { createContext, useContext } from 'react'\n\nconst UserContext = createContext(null)\n\nfunction Greeting() {\n  const user = useContext(UserContext)\n  if (!user) return \u003Cp>Please log in\u003C\u002Fp>\n  return \u003Cp>Hello, {user.name}\u003C\u002Fp>\n}\n\nfunction App() {\n  const [user] = useState({ name: 'Alice' })\n  return (\n    \u003CUserContext.Provider value={user}>\n      \u003CGreeting \u002F>\n    \u003C\u002FUserContext.Provider>\n  )\n}\n```\n\n**Rule of thumb:** `useContext` is the modern replacement for the legacy\n`Context.Consumer` render-prop API. Use it exclusively in function\ncomponents.\n",{"id":139,"difficulty":59,"q":140,"a":141},"context-re-renders","When does a context change cause re-renders, and which components are affected?","Every component that calls `useContext(MyContext)` **re-renders** when\nthe Provider's `value` prop changes (by reference). Intermediate\ncomponents that don't consume the context are **not** re-rendered.\n\n```jsx\nconst CountCtx = createContext(0)\n\nfunction Parent() {\n  const [count, setCount] = useState(0)\n  return (\n    \u002F\u002F Object literal creates a new reference every render — all consumers re-render\n    \u003CCountCtx.Provider value={{ count, setCount }}>\n      \u003CMiddle \u002F>\n    \u003C\u002FCountCtx.Provider>\n  )\n}\n\nfunction Middle() {\n  \u002F\u002F does NOT use CountCtx → NOT re-rendered when count changes\n  return \u003CConsumer \u002F>\n}\n\nfunction Consumer() {\n  const { count } = useContext(CountCtx)   \u002F\u002F re-renders on every count change\n  return \u003Cspan>{count}\u003C\u002Fspan>\n}\n```\n\n**Rule of thumb:** Memoize the context value (`useMemo`) when the\nProvider's parent re-renders frequently to avoid creating a new\nreference each time.\n",{"id":143,"difficulty":59,"q":144,"a":145},"context-value-memo","Why should you memoize the value passed to a Context Provider?","Every time the Provider's parent re-renders, a new object or array\nliteral creates a **new reference**. React's shallow equality check\nsees a new reference → all consumers re-render even if the data\nhasn't changed.\n\n```jsx\n\u002F\u002F ❌ New object every render → all consumers re-render needlessly\n\u003CAuthContext.Provider value={{ user, logout }}>\n\n\u002F\u002F ✅ Stable reference — only changes when user or logout changes\nconst authValue = useMemo(() => ({ user, logout }), [user, logout])\n\u003CAuthContext.Provider value={authValue}>\n```\n\nIf the value is a primitive (string, number) memoisation is\nunnecessary because primitives are compared by value.\n\n**Rule of thumb:** Whenever you pass an object or array as a context\nvalue, wrap it in `useMemo`.\n",{"id":147,"difficulty":59,"q":148,"a":149},"context-multiple","Can a component use multiple contexts, and how do you compose multiple Providers?","Yes. Call `useContext` once per context. Compose Providers by nesting\nthem at the top of the tree — order only matters if a Provider reads\nfrom a sibling context.\n\n```jsx\nfunction App() {\n  return (\n    \u003CThemeContext.Provider value=\"dark\">\n      \u003CAuthContext.Provider value={currentUser}>\n        \u003CLocaleContext.Provider value=\"en\">\n          \u003CRouter \u002F>\n        \u003C\u002FLocaleContext.Provider>\n      \u003C\u002FAuthContext.Provider>\n    \u003C\u002FThemeContext.Provider>\n  )\n}\n\nfunction Header() {\n  const theme  = useContext(ThemeContext)\n  const user   = useContext(AuthContext)\n  const locale = useContext(LocaleContext)\n  \u002F\u002F ...\n}\n```\n\nIf nesting becomes unwieldy, extract a single `AppProviders` wrapper\ncomponent that composes them all.\n\n**Rule of thumb:** Create one context per concern; don't cram unrelated\nvalues into a single context object.\n",{"id":151,"difficulty":59,"q":152,"a":153},"context-vs-props","When should you use Context instead of props?","Use Context when data is needed by **many components at different nesting\nlevels** and passing it via props would require threading it through\nmany intermediate layers that don't need it themselves.\n\n| Signal | Prefer |\n|---|---|\n| 1–2 levels of passing | Props |\n| Truly global (theme, locale, auth) | Context |\n| Frequently changes, many subscribers | External store |\n\n```jsx\n\u002F\u002F Props are fine — shallow tree, one consumer\n\u003CPage>\u003CCard title={title} \u002F>\u003C\u002FPage>\n\n\u002F\u002F Context fits — auth needed everywhere, changes rarely\n\u003CAuthContext.Provider value={user}>\n  \u003CNavbar \u002F>\u003CRoutes \u002F>\u003CFooter \u002F>\n\u003C\u002FAuthContext.Provider>\n```\n\n**Rule of thumb:** If you're passing the same prop through 3+ levels\nthat don't use it, that's the signal to consider Context.\n",{"id":155,"difficulty":59,"q":156,"a":157},"context-vs-redux","What are the main differences between Context and a library like Redux?","| Aspect | Context | Redux \u002F Zustand |\n|---|---|---|\n| Built-in | Yes | External dependency |\n| Re-render granularity | All consumers of the context | Selector-level (only subscribe to what you need) |\n| DevTools | None | Time-travel, action log |\n| Async logic | Manual | Built-in middleware (thunk, saga) |\n| Boilerplate | Low | Medium (RTK reduces it) |\n\nContext is best for **infrequently changing** global values (theme,\nlocale, authenticated user). For **frequently updating** shared state\nwith many subscribers, a store library avoids cascade re-renders.\n\n**Rule of thumb:** Don't reach for Redux just because you have global\nstate. Context + `useReducer` covers a lot of ground; add a store\nwhen you need fine-grained subscriptions or middleware.\n",{"id":159,"difficulty":59,"q":160,"a":161},"context-custom-hook","Why is it a good practice to wrap useContext in a custom hook?","A custom hook hides the context import, adds a helpful error message\nwhen used outside the Provider, and creates a stable API so consumers\ndon't need to know which context backs it.\n\n```jsx\n\u002F\u002F context\u002FThemeContext.jsx\nconst ThemeContext = createContext(null)\n\nexport function ThemeProvider({ children }) {\n  const [theme, setTheme] = useState('dark')\n  return (\n    \u003CThemeContext.Provider value={{ theme, setTheme }}>\n      {children}\n    \u003C\u002FThemeContext.Provider>\n  )\n}\n\nexport function useTheme() {\n  const ctx = useContext(ThemeContext)\n  if (!ctx) throw new Error('useTheme must be used inside ThemeProvider')\n  return ctx\n}\n\n\u002F\u002F Consumer — no context import needed\nconst { theme, setTheme } = useTheme()\n```\n\n**Rule of thumb:** Always export a `useFoo()` hook instead of\nexporting the raw Context object.\n",{"id":163,"difficulty":104,"q":164,"a":165},"context-split-concerns","How can you split a context to avoid unnecessary re-renders when only part of the value changes?","Provide **separate contexts** for state and dispatch (or read vs.\nwrite). Components that only dispatch won't re-render when state\nchanges, and vice versa.\n\n```jsx\nconst CountStateCtx   = createContext(null)\nconst CountDispatchCtx = createContext(null)\n\nfunction CountProvider({ children }) {\n  const [count, dispatch] = useReducer(reducer, 0)\n  return (\n    \u003CCountDispatchCtx.Provider value={dispatch}>\n      \u003CCountStateCtx.Provider value={count}>\n        {children}\n      \u003C\u002FCountStateCtx.Provider>\n    \u003C\u002FCountDispatchCtx.Provider>\n  )\n}\n\n\u002F\u002F Only re-renders when count changes\nfunction Counter()   { return \u003Cspan>{useContext(CountStateCtx)}\u003C\u002Fspan> }\n\n\u002F\u002F Never re-renders due to count changes (dispatch is stable)\nfunction IncrBtn()   { return \u003Cbutton onClick={() => useContext(CountDispatchCtx)({ type: 'inc' })}>+\u003C\u002Fbutton> }\n```\n\n**Rule of thumb:** If your context value has both frequently-changing\nstate and stable callbacks, put them in separate contexts.\n",{"id":167,"difficulty":59,"q":168,"a":169},"context-with-reducer","How do you combine useReducer with Context to implement a lightweight global store?","Keep `useReducer` in a Provider component. Pass state via one context\nand the stable `dispatch` via another (or together if updates are\ninfrequent).\n\n```jsx\nconst StoreCtx = createContext(null)\n\nfunction reducer(state, action) {\n  switch (action.type) {\n    case 'SET_USER': return { ...state, user: action.payload }\n    case 'LOGOUT':   return { ...state, user: null }\n    default:         return state\n  }\n}\n\nexport function StoreProvider({ children }) {\n  const [state, dispatch] = useReducer(reducer, { user: null })\n  const value = useMemo(() => ({ state, dispatch }), [state])\n  return \u003CStoreCtx.Provider value={value}>{children}\u003C\u002FStoreCtx.Provider>\n}\n\nexport const useStore = () => useContext(StoreCtx)\n```\n\nThis pattern gives you Redux-like action dispatch without adding a\ndependency — ideal for small to medium apps.\n\n**Rule of thumb:** `useReducer` + Context is the sweet spot before you\nneed Redux's devtools or middleware.\n",{"id":171,"difficulty":104,"q":172,"a":173},"context-lazy-init","How do you avoid expensive context value recomputation on every render?","Use `useMemo` for objects\u002Farrays passed as the context value, and\n`useCallback` for functions, so React sees a stable reference and\nskips re-rendering consumers.\n\n```jsx\nfunction AuthProvider({ children }) {\n  const [user, setUser] = useState(null)\n\n  const logout = useCallback(() => {\n    setUser(null)\n    api.logout()\n  }, [])                         \u002F\u002F stable function reference\n\n  const value = useMemo(\n    () => ({ user, logout }),\n    [user, logout]               \u002F\u002F recompute only when user changes\n  )\n\n  return \u003CAuthContext.Provider value={value}>{children}\u003C\u002FAuthContext.Provider>\n}\n```\n\n**Rule of thumb:** Any context value that is an object or contains\nfunctions should be memoised at the Provider level.\n",{"id":175,"difficulty":59,"q":176,"a":177},"context-default-null","Should the default value of createContext be null or a sensible fallback, and why?","Using `null` (or `undefined`) as the default forces consumers to handle\nthe \"no Provider\" case explicitly and makes it easy to detect misuse.\nA non-null default value makes the component work outside a Provider,\nwhich is useful for testing and Storybook.\n\n```jsx\n\u002F\u002F null default — consumers must check or use a custom hook with an error\nconst AuthContext = createContext(null)\n\n\u002F\u002F Non-null default — component works in isolation; good for theming\nconst ThemeContext = createContext({ mode: 'light', toggle: () => {} })\n```\n\nChoose based on intent:\n- If the component **cannot** work without a Provider → default `null`,\n  throw in the custom hook.\n- If the component **can** work standalone → provide a real fallback.\n\n**Rule of thumb:** Auth\u002Fsession contexts default to `null`; config\u002Ftheme\ncontexts default to a sensible fallback object.\n",{"id":179,"difficulty":34,"q":180,"a":181},"context-provider-location","Where in the component tree should a Context Provider be placed?","As **low as possible** while still wrapping all consumers. Placing it\ntoo high (e.g. at app root) means unrelated subtrees re-render when\nthe context value changes.\n\n```jsx\n\u002F\u002F ❌ Too high — the entire app re-renders when modal state changes\nfunction App() {\n  const [isOpen, setIsOpen] = useState(false)\n  return (\n    \u003CModalContext.Provider value={{ isOpen, setIsOpen }}>\n      \u003CHeader \u002F>\u003CMain \u002F>\u003CFooter \u002F>\n    \u003C\u002FModalContext.Provider>\n  )\n}\n\n\u002F\u002F ✅ Scoped to the subtree that needs it\nfunction CheckoutPage() {\n  const [isOpen, setIsOpen] = useState(false)\n  return (\n    \u003CModalContext.Provider value={{ isOpen, setIsOpen }}>\n      \u003CCheckoutForm \u002F>\u003CConfirmModal \u002F>\n    \u003C\u002FModalContext.Provider>\n  )\n}\n```\n\n**Rule of thumb:** The Provider should be the lowest ancestor that\ncontains all the components that consume the context.\n",{"id":183,"difficulty":59,"q":184,"a":185},"context-testing","How do you test a component that depends on a Context value?","Wrap the component under test in the Provider and supply a controlled\ntest value. With React Testing Library:\n\n```jsx\nimport { render, screen } from '@testing-library\u002Freact'\nimport { ThemeContext } from '.\u002FThemeContext'\nimport ThemedButton from '.\u002FThemedButton'\n\nfunction renderWithTheme(ui, theme = 'light') {\n  return render(\n    \u003CThemeContext.Provider value={theme}>\n      {ui}\n    \u003C\u002FThemeContext.Provider>\n  )\n}\n\ntest('applies dark class in dark mode', () => {\n  renderWithTheme(\u003CThemedButton \u002F>, 'dark')\n  expect(screen.getByRole('button')).toHaveClass('dark')\n})\n```\n\nAlternatively, if you use the custom-hook pattern, wrap in the real\nProvider component from your codebase.\n\n**Rule of thumb:** Never mock context directly — always wrap with the\nreal Provider so tests exercise the full integration.\n",15,{"description":32},"React Context API interview questions — createContext, useContext, Provider, re-render behaviour, multiple contexts, and when to use Context vs. Redux.","react\u002Fstate-and-data-flow\u002Fcontext-api","Context API","p6lfuFzLj8fO3W-l3h9Fm_ohOc8gnQ0e80jy7K7bRmU",{"id":193,"title":194,"body":195,"description":32,"difficulty":59,"extension":35,"framework":10,"frameworkSlug":8,"meta":199,"navigation":38,"order":20,"path":201,"questions":202,"questionsCount":259,"related":108,"seo":260,"seoDescription":261,"stem":262,"subtopic":263,"topic":19,"topicSlug":21,"updated":113,"__hash__":264},"qa\u002Freact\u002Fstate-and-data-flow\u002Fcontrolled-vs-uncontrolled.md","Controlled Vs Uncontrolled",{"type":29,"value":196,"toc":197},[],{"title":32,"searchDepth":11,"depth":11,"links":198},[],{"subtopicSlug":200},"controlled-vs-uncontrolled","\u002Freact\u002Fstate-and-data-flow\u002Fcontrolled-vs-uncontrolled",[203,207,211,215,219,223,227,231,235,239,243,247,251,255],{"id":204,"difficulty":34,"q":205,"a":206},"controlled-what","What is a controlled component in React?","A **controlled component** is one where React state is the **single\nsource of truth** for the input's value. The displayed value comes from\nstate; every change must go through state via an `onChange` handler.\n\n```jsx\nfunction ControlledInput() {\n  const [value, setValue] = useState('')\n\n  return (\n    \u003Cinput\n      value={value}                         \u002F\u002F state drives the DOM\n      onChange={e => setValue(e.target.value)} \u002F\u002F DOM change updates state\n    \u002F>\n  )\n}\n```\n\nReact keeps the DOM perfectly in sync with state — you can read,\nvalidate, or transform every keystroke before it appears.\n\n**Rule of thumb:** If you need to validate, transform, or react to every\nchange as the user types, use a controlled component.\n",{"id":208,"difficulty":34,"q":209,"a":210},"uncontrolled-what","What is an uncontrolled component in React?","An **uncontrolled component** lets the DOM manage its own state. React\ndoes not drive the input's value — you only read it when you need it\n(typically on submit) using a `ref`.\n\n```jsx\nfunction UncontrolledForm() {\n  const inputRef = useRef(null)\n\n  function handleSubmit(e) {\n    e.preventDefault()\n    console.log(inputRef.current.value)   \u002F\u002F read on demand\n  }\n\n  return (\n    \u003Cform onSubmit={handleSubmit}>\n      \u003Cinput ref={inputRef} defaultValue=\"initial\" \u002F>\n      \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n```\n\nBecause there is no React state involved, uncontrolled inputs are\nsimpler to set up but offer less control over intermediate values.\n\n**Rule of thumb:** Use uncontrolled components for simple forms where\nyou only care about the final submitted value, not intermediate input.\n",{"id":212,"difficulty":34,"q":213,"a":214},"controlled-vs-uncontrolled-key-diff","What is the key difference between the `value` and `defaultValue` props on an input?","| Prop | Type | Behaviour |\n|---|---|---|\n| `value` | Controlled | React always overrides the DOM value; component is controlled |\n| `defaultValue` | Uncontrolled | Sets the initial value once; DOM manages value after that |\n\n```jsx\n\u002F\u002F Controlled — React owns the value at all times\n\u003Cinput value={stateValue} onChange={e => setState(e.target.value)} \u002F>\n\n\u002F\u002F Uncontrolled — React only sets the initial value\n\u003Cinput defaultValue=\"hello\" ref={inputRef} \u002F>\n```\n\nMixing `value` without `onChange` makes the input read-only from the\nuser's perspective (React prevents edits). React will warn you.\n\n**Rule of thumb:** Use `value` when React should own the value;\nuse `defaultValue` when the DOM should own it after mount.\n",{"id":216,"difficulty":34,"q":217,"a":218},"controlled-when-to-use","When should you prefer a controlled component over an uncontrolled one?","Prefer controlled components when you need:\n- **Instant validation** (highlight errors as the user types)\n- **Conditional UI** based on current field value\n- **Dynamic constraints** (disable a button until all fields are valid)\n- **Programmatic value changes** (auto-fill, clear on reset)\n\n```jsx\nfunction EmailField() {\n  const [email, setEmail] = useState('')\n  const isValid = email.includes('@')\n\n  return (\n    \u003C>\n      \u003Cinput\n        value={email}\n        onChange={e => setEmail(e.target.value)}\n        className={isValid ? 'valid' : 'invalid'}\n      \u002F>\n      \u003Cbutton disabled={!isValid}>Subscribe\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\n**Rule of thumb:** Most production forms use controlled inputs because\nthey provide the feedback loop needed for good UX.\n",{"id":220,"difficulty":34,"q":221,"a":222},"uncontrolled-when-to-use","When is an uncontrolled component a better choice?","Uncontrolled inputs are simpler when:\n- You only need the value at submit time (e.g. a basic search box)\n- Integrating with **non-React libraries** that manage their own DOM\n- Handling **file inputs** (`\u003Cinput type=\"file\">` is always uncontrolled\n  because the browser controls the file path for security)\n- Rapid prototyping where wiring up state would slow you down\n\n```jsx\n\u002F\u002F File inputs are always uncontrolled\nfunction FileUpload() {\n  const fileRef = useRef(null)\n\n  function handleUpload() {\n    const file = fileRef.current.files[0]\n    upload(file)\n  }\n\n  return (\n    \u003C>\n      \u003Cinput type=\"file\" ref={fileRef} \u002F>\n      \u003Cbutton onClick={handleUpload}>Upload\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\n**Rule of thumb:** `\u003Cinput type=\"file\">` is always uncontrolled; for\neverything else, default to controlled unless simplicity wins.\n",{"id":224,"difficulty":34,"q":225,"a":226},"controlled-warning-read-only","What warning does React show if you set `value` without an `onChange` handler?","React logs:\n> *\"You provided a `value` prop to a form field without an `onChange`\n> handler. This will render a read-only field.\"*\n\nThe input is effectively frozen — the user types but the DOM value is\nalways reset to `value` by React on every render.\n\n```jsx\n\u002F\u002F ❌ Read-only — React overrides every keystroke\n\u003Cinput value=\"fixed\" \u002F>\n\n\u002F\u002F ✅ Controlled with handler\n\u003Cinput value={state} onChange={e => setState(e.target.value)} \u002F>\n\n\u002F\u002F ✅ Or explicitly read-only with readOnly\n\u003Cinput value=\"fixed\" readOnly \u002F>\n```\n\n**Rule of thumb:** If you pass `value`, you must also pass `onChange`\n(or `readOnly` if intentionally read-only).\n",{"id":228,"difficulty":59,"q":229,"a":230},"controlled-null-value","What happens if you pass `null` or `undefined` as the `value` prop?","Passing `null` or `undefined` makes the input **uncontrolled** — React\ntreats it the same as omitting `value`. If you later switch back to a\nreal value, React warns that you're changing a component from\nuncontrolled to controlled.\n\n```jsx\n\u002F\u002F ❌ Starts uncontrolled (value is null initially)\nconst [text, setText] = useState(null)\n\u003Cinput value={text} onChange={e => setText(e.target.value)} \u002F>\n\u002F\u002F React: \"changing an uncontrolled input to be controlled\"\n\n\u002F\u002F ✅ Always start controlled with an empty string\nconst [text, setText] = useState('')\n\u003Cinput value={text} onChange={e => setText(e.target.value)} \u002F>\n```\n\n**Rule of thumb:** Initialise controlled state with an empty string\n(`''`) rather than `null` or `undefined`.\n",{"id":232,"difficulty":34,"q":233,"a":234},"controlled-textarea-select","How do controlled and uncontrolled patterns apply to textarea and select elements?","The same `value`\u002F`defaultValue` pattern applies to `\u003Ctextarea>` and\n`\u003Cselect>`. React normalises them so they behave consistently.\n\n```jsx\n\u002F\u002F Controlled textarea\n\u003Ctextarea value={text} onChange={e => setText(e.target.value)} \u002F>\n\n\u002F\u002F Controlled select\n\u003Cselect value={selected} onChange={e => setSelected(e.target.value)}>\n  \u003Coption value=\"a\">Option A\u003C\u002Foption>\n  \u003Coption value=\"b\">Option B\u003C\u002Foption>\n\u003C\u002Fselect>\n\n\u002F\u002F Uncontrolled select with initial selection\n\u003Cselect defaultValue=\"b\" ref={selectRef}>\n  \u003Coption value=\"a\">Option A\u003C\u002Foption>\n  \u003Coption value=\"b\">Option B\u003C\u002Foption>\n\u003C\u002Fselect>\n```\n\n**Rule of thumb:** Treat `\u003Ctextarea>` and `\u003Cselect>` exactly like\n`\u003Cinput>` — use `value` for controlled, `defaultValue` for uncontrolled.\n",{"id":236,"difficulty":34,"q":237,"a":238},"controlled-ref-reading","Can you read an uncontrolled input's value without a ref?","Technically yes — via the native form submit event's\n`e.target.elements` map — but `ref` is the idiomatic React approach.\n\n```jsx\n\u002F\u002F Using ref (recommended)\nconst inputRef = useRef(null)\n\u003Cinput ref={inputRef} \u002F>\n\u002F\u002F Read: inputRef.current.value\n\n\u002F\u002F Using the form submit event (also works, no ref needed)\nfunction handleSubmit(e) {\n  e.preventDefault()\n  const value = e.target.elements.username.value\n}\n\u003Cform onSubmit={handleSubmit}>\n  \u003Cinput name=\"username\" \u002F>\n\u003C\u002Fform>\n```\n\nThe `name`-based approach is fine for very simple forms and mirrors\ntraditional HTML form handling.\n\n**Rule of thumb:** Use `ref` for programmatic access during the\ncomponent's lifetime; use `e.target.elements` for one-shot submit\nreading.\n",{"id":240,"difficulty":59,"q":241,"a":242},"controlled-mixed-form","Can a single form have both controlled and uncontrolled inputs?","Technically yes, but it's an anti-pattern. Mixing paradigms makes the\ncode harder to reason about and breaks the \"single source of truth\"\nprinciple.\n\n```jsx\n\u002F\u002F ❌ Confusing mix\nfunction Form() {\n  const [email, setEmail] = useState('')   \u002F\u002F controlled\n  const phoneRef = useRef(null)            \u002F\u002F uncontrolled\n\n  function handleSubmit() {\n    const data = { email, phone: phoneRef.current.value }\n    \u002F\u002F collecting values from two different sources\n  }\n}\n\n\u002F\u002F ✅ Consistent — all controlled or all via refs\n```\n\nIf you choose controlled, keep all fields controlled. If you use a\nlibrary like React Hook Form it manages uncontrolled inputs uniformly.\n\n**Rule of thumb:** Pick one pattern per form and stick to it.\n",{"id":244,"difficulty":59,"q":245,"a":246},"controlled-react-hook-form","How does React Hook Form differ from the traditional controlled component pattern?","React Hook Form uses **uncontrolled inputs by default** (via `ref`),\nsubscribing to change events without storing every keystroke in React\nstate. This results in **fewer re-renders** — the component only\nre-renders when validation state changes or on submit.\n\n```jsx\nimport { useForm } from 'react-hook-form'\n\nfunction SignupForm() {\n  const { register, handleSubmit, formState: { errors } } = useForm()\n\n  return (\n    \u003Cform onSubmit={handleSubmit(data => console.log(data))}>\n      {\u002F* register wires up ref + onChange internally *\u002F}\n      \u003Cinput {...register('email', { required: true })} \u002F>\n      {errors.email && \u003Cspan>Email required\u003C\u002Fspan>}\n      \u003Cbutton type=\"submit\">Sign up\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n```\n\nFor controlled integration use the `Controller` component or\n`useController` hook.\n\n**Rule of thumb:** React Hook Form is the pragmatic choice for\ncomplex forms — it gives controlled-like DX with uncontrolled\nperformance.\n",{"id":248,"difficulty":59,"q":249,"a":250},"controlled-reset","How do you programmatically reset a controlled form to its initial values?","Call the state setter with the original default values. Because the\ninput values are driven by React state, setting state is all you need.\n\n```jsx\nconst INITIAL = { name: '', email: '' }\n\nfunction ProfileForm() {\n  const [form, setForm] = useState(INITIAL)\n\n  function reset() {\n    setForm(INITIAL)    \u002F\u002F inputs snap back to empty\n  }\n\n  return (\n    \u003Cform>\n      \u003Cinput value={form.name}  onChange={e => setForm(p => ({ ...p, name: e.target.value }))} \u002F>\n      \u003Cinput value={form.email} onChange={e => setForm(p => ({ ...p, email: e.target.value }))} \u002F>\n      \u003Cbutton type=\"button\" onClick={reset}>Reset\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n```\n\nFor uncontrolled forms you need to call `inputRef.current.value = ''`\nfor each field manually, which is why controlled inputs are easier to\nreset programmatically.\n\n**Rule of thumb:** Controlled components make reset trivial — just\nrestore state. Uncontrolled forms require manual DOM manipulation.\n",{"id":252,"difficulty":104,"q":253,"a":254},"controlled-dynamic-fields","How do you manage a dynamic list of controlled input fields?","Store the list in state as an array. Each field reads from its array\nslot and writes back using its index or a stable id.\n\n```jsx\nfunction TagsInput() {\n  const [tags, setTags] = useState(['react', 'hooks'])\n\n  function handleChange(index, value) {\n    setTags(prev => prev.map((t, i) => i === index ? value : t))\n  }\n\n  function addTag() {\n    setTags(prev => [...prev, ''])\n  }\n\n  function removeTag(index) {\n    setTags(prev => prev.filter((_, i) => i !== index))\n  }\n\n  return (\n    \u003C>\n      {tags.map((tag, i) => (\n        \u003Cdiv key={i}>\n          \u003Cinput value={tag} onChange={e => handleChange(i, e.target.value)} \u002F>\n          \u003Cbutton onClick={() => removeTag(i)}>✕\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      ))}\n      \u003Cbutton onClick={addTag}>+ Add\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\n**Rule of thumb:** Use stable ids rather than array indices as `key`\nwhen items can be reordered to avoid React losing focus state.\n",{"id":256,"difficulty":34,"q":257,"a":258},"controlled-vs-uncontrolled-interview-summary","How would you summarise the controlled vs. uncontrolled tradeoff in one sentence?","**Controlled** components give React full authority over the input value\nat the cost of wiring up `onChange` state; **uncontrolled** components\nlet the DOM own the value and are simpler to set up but harder to\nintegrate with validation and dynamic UI.\n\n```\nControlled  → React state is truth → more wiring, more power\nUncontrolled → DOM is truth         → less wiring, less control\n```\n\nThe React docs historically recommended controlled components for most\ncases; today, form libraries (React Hook Form) offer a third path that\nis uncontrolled under the hood but feels controlled in the API.\n\n**Rule of thumb:** Default to controlled unless performance or\nthird-party DOM libraries push you toward uncontrolled.\n",14,{"description":32},"React controlled vs uncontrolled components interview questions — value vs defaultValue, refs, form handling, when to use each approach.","react\u002Fstate-and-data-flow\u002Fcontrolled-vs-uncontrolled","Controlled vs Uncontrolled Components","pcInXbHq2wIIioyp57ydXhnhjx7QfGClTxyTTNAfRrI",{"id":266,"title":267,"body":268,"description":32,"difficulty":59,"extension":35,"framework":10,"frameworkSlug":8,"meta":272,"navigation":38,"order":274,"path":275,"questions":276,"questionsCount":259,"related":108,"seo":333,"seoDescription":334,"stem":335,"subtopic":336,"topic":19,"topicSlug":21,"updated":113,"__hash__":337},"qa\u002Freact\u002Fstate-and-data-flow\u002Fprop-drilling-composition.md","Prop Drilling Composition",{"type":29,"value":269,"toc":270},[],{"title":32,"searchDepth":11,"depth":11,"links":271},[],{"subtopicSlug":273},"prop-drilling-composition",4,"\u002Freact\u002Fstate-and-data-flow\u002Fprop-drilling-composition",[277,281,285,289,293,297,301,305,309,313,317,321,325,329],{"id":278,"difficulty":34,"q":279,"a":280},"prop-drilling-what","What is prop drilling in React?","**Prop drilling** is the practice of passing data through multiple\nintermediate components that **don't need it themselves**, just so it\ncan reach a deeply nested consumer.\n\n```jsx\n\u002F\u002F data flows through App → Page → Section → Widget → Button\n\u002F\u002F Page, Section, and Widget never use `user`, they just pass it on\nfunction App()     { return \u003CPage user={user} \u002F> }\nfunction Page({user})    { return \u003CSection user={user} \u002F> }\nfunction Section({user}) { return \u003CWidget user={user} \u002F> }\nfunction Widget({user})  { return \u003CButton user={user} \u002F> }\nfunction Button({user})  { return \u003Cspan>{user.name}\u003C\u002Fspan> }\n```\n\nThe intermediate components become tightly coupled to data they don't\nown, making refactoring painful.\n\n**Rule of thumb:** If a prop passes through two or more components that\ndon't use it, you have a prop drilling problem worth addressing.\n",{"id":282,"difficulty":34,"q":283,"a":284},"prop-drilling-problems","What are the main problems caused by prop drilling?","1. **Coupling** — intermediate components must accept and forward props\n   they don't care about, creating unnecessary dependencies.\n2. **Refactor friction** — adding, removing, or renaming a prop means\n   updating every intermediate layer.\n3. **Readability** — component signatures grow bloated with pass-through\n   props, obscuring the component's real interface.\n4. **Testing burden** — intermediate components must be tested with\n   props they don't use, just to satisfy type signatures.\n\n```jsx\n\u002F\u002F Every time the shape of `user` changes, all three layers must be\n\u002F\u002F updated — even Page and Section which never read user directly\nfunction Page({ user, theme, locale, featureFlags }) { ... }\n```\n\n**Rule of thumb:** The deeper the tree and the more layers a prop\ncrosses, the more painful prop drilling becomes.\n",{"id":286,"difficulty":59,"q":287,"a":288},"prop-drilling-composition-fix","How can component composition solve prop drilling without using Context?","Pass **pre-rendered children** (JSX elements) down instead of raw data.\nThe top-level component builds the element with full access to its own\nscope; intermediate components just place it.\n\n```jsx\n\u002F\u002F Instead of threading `user` through Page → Section → Widget:\n\nfunction App() {\n  return (\n    \u003CPage>\n      \u003CSection>\n        \u003CWidget>\n          \u003CButton user={user} \u002F>   {\u002F* App has direct access to user *\u002F}\n        \u003C\u002FWidget>\n      \u003C\u002FSection>\n    \u003C\u002FPage>\n  )\n}\n\n\u002F\u002F Intermediates accept children and don't know about user\nfunction Page({ children })    { return \u003Cmain>{children}\u003C\u002Fmain> }\nfunction Section({ children }) { return \u003Csection>{children}\u003C\u002Fsection> }\nfunction Widget({ children })  { return \u003Cdiv>{children}\u003C\u002Fdiv> }\n```\n\nReact calls this **inversion of control** — the parent controls what\nthe children render.\n\n**Rule of thumb:** Try the `children` pattern before reaching for\nContext — it often eliminates drilling with zero new abstractions.\n",{"id":290,"difficulty":34,"q":291,"a":292},"prop-drilling-children-prop","What is the `children` prop and how does it enable composition?","`children` is the implicit prop React passes for any JSX content placed\nbetween a component's opening and closing tags. Components that render\n`{children}` act as **layout containers** — they don't need to know\nwhat's inside.\n\n```jsx\nfunction Card({ title, children }) {\n  return (\n    \u003Cdiv className=\"card\">\n      \u003Ch2>{title}\u003C\u002Fh2>\n      \u003Cdiv className=\"card-body\">{children}\u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  )\n}\n\n\u002F\u002F Usage\n\u003CCard title=\"Profile\">\n  \u003CAvatar user={user} \u002F>\n  \u003CBio text={user.bio} \u002F>\n\u003C\u002FCard>\n```\n\n`Card` renders the user-specific components without knowing anything\nabout `user` itself.\n\n**Rule of thumb:** If a component is a structural wrapper (card, modal,\nlayout), always accept `children` rather than a specific content prop.\n",{"id":294,"difficulty":59,"q":295,"a":296},"prop-drilling-slots","What is the \"slot\" pattern in React and how does it differ from just using children?","The slot pattern uses **named props** (each holding a JSX element) to\nplace content in specific regions — like a header slot, footer slot, and\nbody slot — without the component needing to know about the data inside.\n\n```jsx\nfunction Layout({ header, sidebar, children }) {\n  return (\n    \u003Cdiv className=\"layout\">\n      \u003Cheader>{header}\u003C\u002Fheader>\n      \u003Caside>{sidebar}\u003C\u002Faside>\n      \u003Cmain>{children}\u003C\u002Fmain>\n    \u003C\u002Fdiv>\n  )\n}\n\n\u002F\u002F Caller builds each slot with its own data\n\u003CLayout\n  header={\u003CNavBar user={user} \u002F>}\n  sidebar={\u003CUserMenu user={user} \u002F>}\n>\n  \u003CFeed posts={posts} \u002F>\n\u003C\u002FLayout>\n```\n\n`Layout` remains generic; the caller composes what goes into each slot.\n\n**Rule of thumb:** Use named slots when a layout component has multiple\ndistinct areas that need different content.\n",{"id":298,"difficulty":59,"q":299,"a":300},"prop-drilling-context-solution","When does composition not solve prop drilling and Context becomes necessary?","Composition fails (or becomes awkward) when:\n- The consuming component is **many levels deep** and you would need to\n  thread JSX through too many layers to compose it at the top.\n- The consuming component is in a **third-party library** or a **route**\n  you don't control.\n- The data is needed by **many unrelated subtrees** (e.g. current user,\n  theme, locale).\n\n```jsx\n\u002F\u002F If Button is inside a deeply nested third-party table cell,\n\u002F\u002F you can't easily pass it as a child from the top.\n\u002F\u002F Context is the right tool here.\nconst UserContext = createContext(null)\n\nfunction App() {\n  return (\n    \u003CUserContext.Provider value={user}>\n      \u003CThirdPartyTable columns={columns} \u002F>\n    \u003C\u002FUserContext.Provider>\n  )\n}\n\nfunction CustomCell() {\n  const user = useContext(UserContext)\n  return \u003CButton>{user.name}\u003C\u002FButton>\n}\n```\n\n**Rule of thumb:** Try composition first. Reach for Context when the\nconsumer and the data owner are architecturally disconnected.\n",{"id":302,"difficulty":59,"q":303,"a":304},"prop-drilling-render-props","What are render props and how do they help with composition?","A **render prop** is a prop whose value is a function that returns JSX.\nThe component calls the function at render time, passing internal state\nor logic to the caller.\n\n```jsx\nfunction MouseTracker({ render }) {\n  const [pos, setPos] = useState({ x: 0, y: 0 })\n\n  return (\n    \u003Cdiv onMouseMove={e => setPos({ x: e.clientX, y: e.clientY })}>\n      {render(pos)}    {\u002F* caller decides what to show *\u002F}\n    \u003C\u002Fdiv>\n  )\n}\n\n\u002F\u002F Usage — no prop drilling; the caller gets the data it needs\n\u003CMouseTracker render={({ x, y }) => \u003CCursor x={x} y={y} \u002F>} \u002F>\n```\n\nRender props share logic without a component hierarchy, but they can\nlead to deeply nested JSX (\"callback hell\"). Custom hooks have largely\nreplaced them for logic sharing.\n\n**Rule of thumb:** Prefer custom hooks for sharing stateful logic; use\nrender props only when you need to inject JSX into a component that\ncontrols lifecycle.\n",{"id":306,"difficulty":59,"q":307,"a":308},"prop-drilling-hoc","How do Higher-Order Components (HOCs) relate to prop drilling?","An **HOC** is a function that takes a component and returns a new\ncomponent with extra props injected. They were the pre-hooks solution\nfor sharing logic without drilling, but they add indirection and can\nconflict with prop names.\n\n```jsx\nfunction withUser(Component) {\n  return function WrappedComponent(props) {\n    const user = useContext(UserContext)\n    return \u003CComponent {...props} user={user} \u002F>\n  }\n}\n\nconst ProfileWithUser = withUser(Profile)\n\u002F\u002F Profile receives user without the caller drilling it\n```\n\nHOCs are still used in third-party libraries (React-Redux's `connect`)\nbut custom hooks are preferred for new code.\n\n**Rule of thumb:** Write a custom hook first. Only reach for an HOC\nwhen the consuming component is a class component or you need to inject\ninto a component you don't own.\n",{"id":310,"difficulty":59,"q":311,"a":312},"prop-drilling-avoid-global","Is it always wrong to pass a prop through an intermediate component?","No. Passing props **one level down** is perfectly fine and is often the\nclearest approach. Prop drilling is only a problem when it spans many\nlayers **and** the intermediate components have no other reason to know\nabout the prop.\n\n```jsx\n\u002F\u002F Fine — one level, clear intent\nfunction ProductPage({ product }) {\n  return \u003CProductCard product={product} \u002F>\n}\n\n\u002F\u002F Problem — three layers, none of them use `user`\nfunction ProductPage({ product, user }) {\n  return \u003CProductCard product={product} user={user} \u002F>\n}\nfunction ProductCard({ product, user }) {\n  return \u003CSaveButton user={user} \u002F>\n}\nfunction SaveButton({ user }) {\n  return \u003Cbutton disabled={!user.isPremium}>Save\u003C\u002Fbutton>\n}\n```\n\n**Rule of thumb:** One level is fine. Two levels — consider composition.\nThree or more — seriously evaluate Context or composition.\n",{"id":314,"difficulty":59,"q":315,"a":316},"prop-drilling-colocate","How can co-locating state close to where it's used reduce prop drilling?","If state is lifted higher than it needs to be, every component between\nthe owner and the consumer has to forward it. Moving state **down** to\nthe component that actually needs it eliminates the intermediate passes.\n\n```jsx\n\u002F\u002F ❌ modal state lives in App, drills through Header → Nav → MenuButton\nfunction App() {\n  const [isMenuOpen, setIsMenuOpen] = useState(false)\n  return \u003CHeader isMenuOpen={isMenuOpen} onToggle={setIsMenuOpen} \u002F>\n}\n\n\u002F\u002F ✅ menu state lives where it belongs — no drilling\nfunction Nav() {\n  const [isMenuOpen, setIsMenuOpen] = useState(false)\n  return \u003CMenuButton open={isMenuOpen} onToggle={setIsMenuOpen} \u002F>\n}\n```\n\nState co-location is the inverse of \"lift state up\" — lift only when\ntwo siblings need the same state; keep it local otherwise.\n\n**Rule of thumb:** Before reaching for Context, ask \"Can I just move\nthis state down to where it's used?\"\n",{"id":318,"difficulty":104,"q":319,"a":320},"prop-drilling-zustand","How does a library like Zustand solve prop drilling compared to Context?","Zustand creates a **store outside React's component tree**. Any\ncomponent can subscribe directly with a selector and only re-renders\nwhen its selected slice changes — no Provider needed, no intermediate\nforwarding.\n\n```jsx\nimport { create } from 'zustand'\n\nconst useUserStore = create(set => ({\n  user: null,\n  setUser: user => set({ user }),\n}))\n\n\u002F\u002F Any component anywhere in the tree — no Provider, no drilling\nfunction Button() {\n  const user = useUserStore(state => state.user)\n  return \u003Cspan>{user?.name}\u003C\u002Fspan>\n}\n```\n\nUnlike Context, Zustand subscriptions are selector-scoped — a component\nonly re-renders when its selected slice actually changes.\n\n**Rule of thumb:** Add Zustand (or Redux Toolkit) when Context re-render\nperformance becomes a real problem or when you need devtools \u002F\nmiddleware.\n",{"id":322,"difficulty":34,"q":323,"a":324},"prop-drilling-summary","What are the four main solutions to prop drilling, ordered by complexity?","1. **Co-location** — move state down so it lives closer to the consumer.\n2. **Composition \u002F children** — pass pre-rendered JSX or named slots so\n   intermediate components don't need to know about the data.\n3. **Context API** — share data across a subtree without prop passing,\n   best for infrequently changing global values.\n4. **External store** (Zustand, Redux) — selector-scoped subscriptions\n   for frequently changing data with many consumers.\n\n```\nCo-location   → simplest, no overhead\nComposition   → good DX, no new abstractions\nContext       → built-in, okay for infrequent updates\nStore library → scalable, selector performance, devtools\n```\n\n**Rule of thumb:** Solve at the lowest complexity level that works.\nDon't jump to Redux because you read about prop drilling; try\ncomposition first.\n",{"id":326,"difficulty":34,"q":327,"a":328},"prop-drilling-types","What TypeScript pattern helps make prop-forwarding components less painful?","Use **rest props spread** (`...props`) combined with a specific type\nfor your own props, so the component forwards everything else without\nlisting every forwarded prop explicitly.\n\n```tsx\nimport { ButtonHTMLAttributes } from 'react'\n\ninterface IconButtonProps extends ButtonHTMLAttributes\u003CHTMLButtonElement> {\n  icon: string   \u002F\u002F own prop\n}\n\nfunction IconButton({ icon, ...rest }: IconButtonProps) {\n  return (\n    \u003Cbutton {...rest}>\n      \u003Ci className={`icon-${icon}`} \u002F>\n      {rest.children}\n    \u003C\u002Fbutton>\n  )\n}\n\n\u002F\u002F Caller can pass onClick, disabled, aria-label without drilling each one\n\u003CIconButton icon=\"save\" onClick={save} disabled={!dirty} \u002F>\n```\n\nThis pattern is especially useful for wrapper components around native\nelements.\n\n**Rule of thumb:** Extend `HTMLAttributes` and spread `...rest` for any\ncomponent that wraps a native element.\n",{"id":330,"difficulty":104,"q":331,"a":332},"prop-drilling-compound","How does the compound component pattern reduce prop drilling inside a component family?","Compound components use **implicit Context** to share state between a\nparent and its child sub-components — the caller doesn't need to wire\nup any props between them.\n\n```jsx\nconst AccordionCtx = createContext(null)\n\nfunction Accordion({ children }) {\n  const [openId, setOpenId] = useState(null)\n  return (\n    \u003CAccordionCtx.Provider value={{ openId, setOpenId }}>\n      \u003Cdiv>{children}\u003C\u002Fdiv>\n    \u003C\u002FAccordionCtx.Provider>\n  )\n}\n\nAccordion.Item = function Item({ id, title, children }) {\n  const { openId, setOpenId } = useContext(AccordionCtx)\n  const isOpen = openId === id\n  return (\n    \u003Cdiv>\n      \u003Cbutton onClick={() => setOpenId(isOpen ? null : id)}>{title}\u003C\u002Fbutton>\n      {isOpen && \u003Cdiv>{children}\u003C\u002Fdiv>}\n    \u003C\u002Fdiv>\n  )\n}\n\n\u002F\u002F Usage — no prop drilling between Accordion and Item\n\u003CAccordion>\n  \u003CAccordion.Item id=\"a\" title=\"Section A\">Content A\u003C\u002FAccordion.Item>\n  \u003CAccordion.Item id=\"b\" title=\"Section B\">Content B\u003C\u002FAccordion.Item>\n\u003C\u002FAccordion>\n```\n\n**Rule of thumb:** Use the compound component pattern for component\nfamilies (tabs, accordions, dropdowns) that need shared state but want\na clean JSX API.\n",{"description":32},"React prop drilling interview questions — what it is, why it hurts, and how to fix it with composition, Context, children props, and slot patterns.","react\u002Fstate-and-data-flow\u002Fprop-drilling-composition","Prop Drilling and Composition","lSE3CKtjSCZ0yfQ1sTV2AfbxI21sv2LXPhVBiKlk7jg",1782244096639]