[{"data":1,"prerenderedAt":504},["ShallowReactive",2],{"topic-react-patterns":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-patterns.yml","Compound components, render props, HOCs, error boundaries, portals, refs, forwardRef, and useImperativeHandle — React advanced composition patterns for building flexible, reusable, and production-grade component APIs.",{},"Patterns",7,"patterns","topics\u002Freact-patterns","KARW213p_6I5xERIsw65KJCRrzpUp6VCKogaXYue-eM",[25,125,216,312,408],{"id":26,"title":27,"body":28,"description":32,"difficulty":34,"extension":35,"framework":10,"frameworkSlug":8,"meta":36,"navigation":37,"order":13,"path":38,"questions":39,"questionsCount":118,"related":119,"seo":120,"seoDescription":121,"stem":122,"subtopic":27,"topic":19,"topicSlug":21,"updated":123,"__hash__":124},"qa\u002Freact\u002Fpatterns\u002Fcompound-components.md","Compound Components",{"type":29,"value":30,"toc":31},"minimark",[],{"title":32,"searchDepth":11,"depth":11,"links":33},"",[],"medium","md",{},true,"\u002Freact\u002Fpatterns\u002Fcompound-components",[40,45,49,53,57,61,65,69,73,77,81,85,89,93,98,102,106,110,114],{"id":41,"difficulty":42,"q":43,"a":44},"what-are-compound-components","easy","What are compound components and what problem do they solve?","**Compound components** are a set of components that work together to form a cohesive UI\nunit while sharing state implicitly. The parent component owns the state; child\nsub-components consume it without the consumer having to wire it up manually.\n\nThe problem they solve is **prop explosion** on monolithic components. Consider a `\u003CTabs>`\ncomponent — without the pattern you end up passing `tabs`, `activeTab`, `onTabChange`,\n`renderPanel`, and more as props. With compound components the API becomes declarative:\n\n```jsx\n\u002F\u002F Monolithic: consumer must juggle every prop\n\u003CTabs\n  tabs={[{ label: 'A', content: \u003Cdiv \u002F> }]}\n  activeTab={active}\n  onTabChange={setActive}\n\u002F>\n\n\u002F\u002F Compound: consumer composes sub-components freely\n\u003CTabs defaultValue=\"a\">\n  \u003CTabs.List>\n    \u003CTabs.Tab value=\"a\">Tab A\u003C\u002FTabs.Tab>\n    \u003CTabs.Tab value=\"b\">Tab B\u003C\u002FTabs.Tab>\n  \u003C\u002FTabs.List>\n  \u003CTabs.Panel value=\"a\">Content A\u003C\u002FTabs.Panel>\n  \u003CTabs.Panel value=\"b\">Content B\u003C\u002FTabs.Panel>\n\u003C\u002FTabs>\n```\n\n**Rule of thumb:** Reach for compound components when multiple tightly related pieces of\nUI need to share state but the caller should control their layout and composition.\n",{"id":46,"difficulty":42,"q":47,"a":48},"context-based-state-sharing","How do compound sub-components share state without prop drilling?","The standard approach is a **dedicated Context** created inside the compound component\nmodule. The parent component provides the shared state; sub-components consume it via\n`useContext`. This keeps the shared state invisible to the consumer of the component.\n\n```jsx\n\u002F\u002F 1. Create context (not exported — internal implementation detail)\nconst TabsContext = createContext(null);\n\n\u002F\u002F 2. Parent provides state\nfunction Tabs({ defaultValue, children }) {\n  const [active, setActive] = useState(defaultValue);\n  return (\n    \u003CTabsContext.Provider value={{ active, setActive }}>\n      {children}\n    \u003C\u002FTabsContext.Provider>\n  );\n}\n\n\u002F\u002F 3. Sub-components consume without any extra props from caller\nfunction TabsTab({ value, children }) {\n  const { active, setActive } = useContext(TabsContext);\n  return (\n    \u003Cbutton\n      aria-selected={active === value}\n      onClick={() => setActive(value)}\n    >\n      {children}\n    \u003C\u002Fbutton>\n  );\n}\n```\n\n**Rule of thumb:** Keep the Context object private to the module; export only the\nsub-components so consumers never reach into internal state directly.\n",{"id":50,"difficulty":42,"q":51,"a":52},"dot-notation-api","What is the dot-notation API pattern and how do you set it up?","**Dot-notation** attaches sub-components as static properties on the parent component\n(`Menu.Item`, `Tabs.Panel`). This groups related components under a single import and\nmakes the relationship obvious in JSX.\n\n```jsx\n\u002F\u002F Attach sub-components as static properties\nfunction Tabs({ defaultValue, children }) { \u002F* ... *\u002F }\n\nTabs.List  = function TabsList({ children }) { \u002F* ... *\u002F };\nTabs.Tab   = function TabsTab({ value, children }) { \u002F* ... *\u002F };\nTabs.Panel = function TabsPanel({ value, children }) { \u002F* ... *\u002F };\n\nexport default Tabs;\n\n\u002F\u002F Consumer imports one name, uses all four components\nimport Tabs from '.\u002FTabs';\n\n\u003CTabs defaultValue=\"a\">\n  \u003CTabs.List>\n    \u003CTabs.Tab value=\"a\">A\u003C\u002FTabs.Tab>\n  \u003C\u002FTabs.List>\n  \u003CTabs.Panel value=\"a\">Content\u003C\u002FTabs.Panel>\n\u003C\u002FTabs>\n```\n\nAn alternative is named exports (`export { Tabs, TabsList, TabsTab, TabsPanel }`) which\nworks well with tree-shaking but loses the visual grouping at the import site.\n\n**Rule of thumb:** Use dot-notation for libraries or shared design system components;\nnamed exports are fine for single-app usage where IDE autocomplete fills the gap.\n",{"id":54,"difficulty":34,"q":55,"a":56},"react-children-traversal","What is the React.Children traversal approach to compound components and what are its drawbacks?","Before Context, a common technique was **`React.Children.map`** with `React.cloneElement`\nto inject props directly into child elements. The parent inspects its children and injects\nthe shared state as additional props.\n\n```jsx\nfunction Tabs({ defaultValue, children }) {\n  const [active, setActive] = useState(defaultValue);\n\n  return (\n    \u003Cdiv>\n      {React.Children.map(children, child => {\n        if (!React.isValidElement(child)) return child;\n        \u002F\u002F Inject active\u002FsetActive into every direct child\n        return React.cloneElement(child, { active, setActive });\n      })}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nKey drawbacks:\n- **Breaks with nesting** — `cloneElement` only reaches direct children; wrapping a\n  `\u003CTabs.Tab>` in a `\u003Cdiv>` for layout breaks the injection chain.\n- **Type safety is lost** — injected props are not reflected in the child component's\n  declared prop types.\n- **Performance** — clones every child on every render even if state did not change.\n- **Fragile** — relies on element identity checks that break with HOCs or memoized\n  wrappers.\n\n**Rule of thumb:** Prefer Context over `cloneElement` for new compound components;\n`cloneElement` is a legacy pattern kept alive only to understand older codebases.\n",{"id":58,"difficulty":34,"q":59,"a":60},"controlled-vs-uncontrolled-compound","How do you make a compound component support both controlled and uncontrolled modes?","Follow the same **controlled\u002Funcontrolled duality** used by HTML inputs: accept an\noptional `value` + `onChange` for controlled mode, and a `defaultValue` for uncontrolled.\nInside the component, maintain internal state only when the caller passes no `value`.\n\n```jsx\nfunction Tabs({ value, defaultValue, onChange, children }) {\n  \u002F\u002F Internal state only used in uncontrolled mode\n  const [internalActive, setInternalActive] = useState(defaultValue ?? null);\n\n  \u002F\u002F Controlled if `value` prop is provided\n  const isControlled = value !== undefined;\n  const active = isControlled ? value : internalActive;\n\n  function handleChange(next) {\n    if (!isControlled) setInternalActive(next); \u002F\u002F update internal state\n    onChange?.(next);                            \u002F\u002F always notify caller\n  }\n\n  return (\n    \u003CTabsContext.Provider value={{ active, handleChange }}>\n      {children}\n    \u003C\u002FTabsContext.Provider>\n  );\n}\n```\n\n**Rule of thumb:** A component is controlled when the caller owns the value prop; never\nswitch between modes at runtime — log a warning if `value` goes from defined to undefined.\n",{"id":62,"difficulty":34,"q":63,"a":64},"implicit-vs-explicit-state","What is the difference between implicit and explicit state sharing in compound components?","**Implicit sharing** (via Context) hides the wiring from the consumer. Sub-components\nreach into Context themselves — the consumer never passes state between siblings.\n\n**Explicit sharing** means the consumer manually threads state as props, typically using\n`render props` or a `children` function pattern:\n\n```jsx\n\u002F\u002F Explicit — caller owns and passes state\n\u003CTabs>\n  {({ active, setActive }) => (\n    \u003C>\n      \u003CTabList active={active} onSelect={setActive} \u002F>\n      \u003CTabPanel active={active} \u002F>\n    \u003C\u002F>\n  )}\n\u003C\u002FTabs>\n\n\u002F\u002F Implicit — Context handles the wiring\n\u003CTabs defaultValue=\"a\">\n  \u003CTabs.List>\n    \u003CTabs.Tab value=\"a\">A\u003C\u002FTabs.Tab>  {\u002F* reads Context internally *\u002F}\n  \u003C\u002FTabs.List>\n  \u003CTabs.Panel value=\"a\">Content\u003C\u002FTabs.Panel>\n\u003C\u002FTabs>\n```\n\nImplicit sharing produces cleaner JSX and is the hallmark of the compound components\npattern. Explicit sharing via render props is more flexible (state is available anywhere\nin the subtree) but transfers more complexity to the consumer.\n\n**Rule of thumb:** Use implicit Context sharing for encapsulated design-system components;\nuse render props when the consumer genuinely needs access to internal state for custom logic.\n",{"id":66,"difficulty":42,"q":67,"a":68},"custom-hook-for-context","Why and how do you wrap a compound component's Context in a custom hook?","Wrapping the Context in a **custom hook** adds a guard that throws a descriptive error\nwhen a sub-component is used outside its parent. This is far easier to debug than the\nsilent `null` that `useContext` returns for a missing provider.\n\n```jsx\nconst TabsContext = createContext(null);\n\n\u002F\u002F Custom hook with guard\nfunction useTabs() {\n  const ctx = useContext(TabsContext);\n  if (!ctx) {\n    throw new Error(\n      'useTabs must be used within a \u003CTabs> component'\n    );\n  }\n  return ctx;\n}\n\n\u002F\u002F Sub-components use the guarded hook, not useContext directly\nfunction TabsTab({ value, children }) {\n  const { active, handleChange } = useTabs(); \u002F\u002F throws if misused\n  return (\n    \u003Cbutton onClick={() => handleChange(value)}>\n      {children}\n    \u003C\u002Fbutton>\n  );\n}\n```\n\n**Rule of thumb:** Always export the custom hook rather than the Context object; this\nprevents consumers from bypassing the guard and simplifies future refactors.\n",{"id":70,"difficulty":34,"q":71,"a":72},"typescript-typing","How do you type a compound component API with TypeScript?","You need to type three things: the **Context shape**, the **sub-component props**, and\nthe **parent component augmented with its sub-component statics**.\n\n```tsx\n\u002F\u002F 1. Type the shared context\ninterface TabsContextValue {\n  active: string;\n  handleChange: (value: string) => void;\n}\nconst TabsContext = createContext\u003CTabsContextValue | null>(null);\n\n\u002F\u002F 2. Type each sub-component normally\ninterface TabsTabProps {\n  value: string;\n  children: React.ReactNode;\n}\nfunction TabsTab({ value, children }: TabsTabProps) { \u002F* ... *\u002F }\n\n\u002F\u002F 3. Augment the parent type with static properties\ninterface TabsComponent extends React.FC\u003CTabsProps> {\n  List:  React.FC\u003C{ children: React.ReactNode }>;\n  Tab:   React.FC\u003CTabsTabProps>;\n  Panel: React.FC\u003C{ value: string; children: React.ReactNode }>;\n}\n\nconst Tabs = function Tabs({ defaultValue, children }: TabsProps) {\n  \u002F* ... *\u002F\n} as TabsComponent;\n\nTabs.List  = TabsList;\nTabs.Tab   = TabsTab;\nTabs.Panel = TabsPanel;\n```\n\n**Rule of thumb:** Use a named interface that extends `React.FC\u003CProps>` to attach\nsub-component types; this gives consumers full autocomplete on `\u003CTabs.` in the editor.\n",{"id":74,"difficulty":42,"q":75,"a":76},"real-world-accordion","Describe the compound component structure for an Accordion.","An **Accordion** is a natural fit: the root tracks which item(s) are expanded; each\n`Accordion.Item` provides a nested sub-Context for its own `value`; `Accordion.Trigger`\ntoggles expansion; `Accordion.Content` conditionally renders.\n\n```jsx\n\u002F\u002F Root: tracks open items\nfunction Accordion({ type = 'single', children }) {\n  const [open, setOpen] = useState(new Set());\n  function toggle(value) {\n    setOpen(prev => {\n      const next = new Set(type === 'single' ? [] : prev);\n      prev.has(value) ? next.delete(value) : next.add(value);\n      return next;\n    });\n  }\n  return (\n    \u003CAccordionContext.Provider value={{ open, toggle }}>\n      {children}\n    \u003C\u002FAccordionContext.Provider>\n  );\n}\n\n\u002F\u002F Item: provides its own value to children via a second context\nAccordion.Item = function AccordionItem({ value, children }) {\n  return (\n    \u003CAccordionItemContext.Provider value={value}>\n      {children}\n    \u003C\u002FAccordionItemContext.Provider>\n  );\n};\n\n\u002F\u002F Trigger reads item context to know which value to toggle\nAccordion.Trigger = function AccordionTrigger({ children }) {\n  const value  = useContext(AccordionItemContext);\n  const { open, toggle } = useAccordion();\n  return (\n    \u003Cbutton aria-expanded={open.has(value)} onClick={() => toggle(value)}>\n      {children}\n    \u003C\u002Fbutton>\n  );\n};\n```\n\n**Rule of thumb:** Nested Context layers are fine — use one for the collection-level\nstate and one for each item's identity; keep both Context objects private.\n",{"id":78,"difficulty":34,"q":79,"a":80},"flexible-composition","How does the compound component pattern enable flexible composition that monolithic components cannot?","With a monolithic component the **layout is fixed** — the component renders its own\nmarkup structure. With compound components the **consumer controls the layout** by placing\nsub-components anywhere in JSX, interspersing other elements freely.\n\n```jsx\n\u002F\u002F Monolithic: layout is baked in, no way to add a badge next to a tab label\n\u003CTabs tabs={[{ label: 'A' }, { label: 'B' }]} \u002F>\n\n\u002F\u002F Compound: consumer inserts arbitrary content between or inside sub-components\n\u003CTabs defaultValue=\"a\">\n  \u003Cheader className=\"flex justify-between\">\n    \u003CTabs.List>\n      \u003CTabs.Tab value=\"a\">\n        Dashboard \u003CBadge count={3} \u002F> {\u002F* freely inserted *\u002F}\n      \u003C\u002FTabs.Tab>\n      \u003CTabs.Tab value=\"b\">Settings\u003C\u002FTabs.Tab>\n    \u003C\u002FTabs.List>\n    \u003CUserMenu \u002F>  {\u002F* unrelated element, same row *\u002F}\n  \u003C\u002Fheader>\n\n  \u003CTabs.Panel value=\"a\">\u003CDashboardContent \u002F>\u003C\u002FTabs.Panel>\n  \u003CTabs.Panel value=\"b\">\u003CSettingsContent \u002F>\u003C\u002FTabs.Panel>\n\u003C\u002FTabs>\n```\n\n**Rule of thumb:** If different callers need different layouts or want to inject elements\nbetween parts of a component, compound components are the right abstraction; if every\ncaller wants the same layout, a simpler prop-driven component is sufficient.\n",{"id":82,"difficulty":42,"q":83,"a":84},"when-not-to-use","When should you NOT use the compound component pattern?","Compound components add indirection and a module-level Context. They are the wrong choice\nwhen:\n\n- **The component is simple** — a `\u003CButton>` with a loading state does not warrant a\n  compound API; a single `loading` boolean prop is clearer.\n- **Sub-components are always rendered together** — if callers never need to rearrange the\n  parts, the flexibility is overhead with no benefit.\n- **Server components** — React Server Components cannot use Context, so the pattern\n  requires pushing the compound root to a client boundary.\n- **Over-engineering** — a team unfamiliar with the pattern will find it harder to\n  maintain than a straightforward props API.\n\n```jsx\n\u002F\u002F Overkill — compound component for something trivially prop-driven\n\u003CButton.Root>\n  \u003CButton.Icon name=\"save\" \u002F>\n  \u003CButton.Label>Save\u003C\u002FButton.Label>\n\u003C\u002FButton.Root>\n\n\u002F\u002F Just use props\n\u003CButton icon=\"save\" loading={saving}>Save\u003C\u002FButton>\n```\n\n**Rule of thumb:** Use compound components when callers regularly need layout control\nover multiple coordinated sub-pieces; prefer simple props when one \"shape\" serves everyone.\n",{"id":86,"difficulty":34,"q":87,"a":88},"select-compound-example","Walk through a minimal compound component implementation of a custom Select.","A custom **Select** needs: the root to track open\u002Fvalue state; a `Trigger` to open the\ndropdown; a `List` to contain options; and `Option` items that close the list on selection.\n\n```jsx\nconst SelectCtx = createContext(null);\nfunction useSelect() {\n  const ctx = useContext(SelectCtx);\n  if (!ctx) throw new Error('Must be inside \u003CSelect>');\n  return ctx;\n}\n\nfunction Select({ value, onChange, children }) {\n  const [open, setOpen] = useState(false);\n  return (\n    \u003CSelectCtx.Provider value={{ value, onChange, open, setOpen }}>\n      \u003Cdiv className=\"relative\">{children}\u003C\u002Fdiv>\n    \u003C\u002FSelectCtx.Provider>\n  );\n}\n\nSelect.Trigger = function SelectTrigger({ children }) {\n  const { value, open, setOpen } = useSelect();\n  return (\n    \u003Cbutton onClick={() => setOpen(o => !o)} aria-haspopup=\"listbox\">\n      {value ?? children}  {\u002F* show selected value or placeholder *\u002F}\n    \u003C\u002Fbutton>\n  );\n};\n\nSelect.Option = function SelectOption({ value, children }) {\n  const { onChange, setOpen } = useSelect();\n  return (\n    \u003Cli\n      role=\"option\"\n      onClick={() => { onChange(value); setOpen(false); }}\n    >\n      {children}\n    \u003C\u002Fli>\n  );\n};\n```\n\n**Rule of thumb:** For accessible custom selects, layer the compound pattern on top of\n`aria-*` attributes rather than replacing native `\u003Cselect>` unless custom styling\ngenuinely requires it.\n",{"id":90,"difficulty":34,"q":91,"a":92},"menu-compound-example","How would you implement a compound Menu component with keyboard navigation?","A **Menu** follows the same Context pattern but adds `useRef` and keyboard event handling\nto support arrow-key navigation and focus management.\n\n```jsx\nconst MenuCtx = createContext(null);\n\nfunction Menu({ children }) {\n  const [open, setOpen]       = useState(false);\n  const [focused, setFocused] = useState(0);\n  const itemRefs              = useRef([]);\n\n  function handleKeyDown(e) {\n    if (e.key === 'ArrowDown') {\n      const next = (focused + 1) % itemRefs.current.length;\n      setFocused(next);\n      itemRefs.current[next]?.focus(); \u002F\u002F move DOM focus\n    }\n    if (e.key === 'Escape') setOpen(false);\n  }\n\n  return (\n    \u003CMenuCtx.Provider value={{ open, setOpen, focused, setFocused, itemRefs }}>\n      \u003Cdiv onKeyDown={handleKeyDown}>{children}\u003C\u002Fdiv>\n    \u003C\u002FMenuCtx.Provider>\n  );\n}\n\nMenu.Item = function MenuItem({ index, onSelect, children }) {\n  const { itemRefs } = useContext(MenuCtx);\n  return (\n    \u003Cbutton\n      ref={el => (itemRefs.current[index] = el)} \u002F\u002F register ref\n      role=\"menuitem\"\n      tabIndex={-1}\n      onClick={onSelect}\n    >\n      {children}\n    \u003C\u002Fbutton>\n  );\n};\n```\n\n**Rule of thumb:** Store an array of item refs in the root Context so the root's\n`keyDown` handler can programmatically focus items without each item knowing about\nits siblings.\n",{"id":94,"difficulty":95,"q":96,"a":97},"default-context-value","hard","What should you pass as the default value to createContext in a compound component and why?","The **default Context value** is used only when a component renders outside any matching\n`Provider` — which for compound components means the sub-component is being used\nincorrectly. There are two schools of thought:\n\n1. **`null` + runtime guard** (recommended): pass `null` as the default and throw in the\n   custom hook. This surfaces misuse as a clear error rather than a silent `undefined`.\n\n2. **Typed fallback**: provide a full default shape. This prevents errors but silently\n   allows misuse, making bugs hard to trace.\n\n```tsx\n\u002F\u002F Option 1: null default + guard (preferred)\nconst TabsCtx = createContext\u003CTabsContextValue | null>(null);\n\nfunction useTabs(): TabsContextValue {\n  const ctx = useContext(TabsCtx);\n  if (ctx === null) {\n    throw new Error('\u003CTabs.Tab> must be rendered inside \u003CTabs>');\n  }\n  return ctx;\n}\n\n\u002F\u002F Option 2: full default (use only for optional composition)\nconst TabsCtx = createContext\u003CTabsContextValue>({\n  active: '',\n  handleChange: () => {},  \u002F\u002F no-op silently\n});\n```\n\n**Rule of thumb:** Use `null` with a guard for required compound parents; use a no-op\ndefault only when a sub-component is genuinely optional (e.g., a tooltip that renders\nstandalone without a parent wrapper).\n",{"id":99,"difficulty":34,"q":100,"a":101},"testing-compound-components","How do you test compound components with React Testing Library?","Test compound components **through their full composed API** — render the parent with\nsub-components just as a consumer would. Avoid importing and rendering sub-components\nin isolation because they depend on the Context being present.\n\n```jsx\nimport { render, screen } from '@testing-library\u002Freact';\nimport userEvent from '@testing-library\u002Fuser-event';\nimport Tabs from '.\u002FTabs';\n\ntest('switches active panel on tab click', async () => {\n  render(\n    \u003CTabs defaultValue=\"a\">\n      \u003CTabs.List>\n        \u003CTabs.Tab value=\"a\">Tab A\u003C\u002FTabs.Tab>\n        \u003CTabs.Tab value=\"b\">Tab B\u003C\u002FTabs.Tab>\n      \u003C\u002FTabs.List>\n      \u003CTabs.Panel value=\"a\">Content A\u003C\u002FTabs.Panel>\n      \u003CTabs.Panel value=\"b\">Content B\u003C\u002FTabs.Panel>\n    \u003C\u002FTabs>\n  );\n\n  \u002F\u002F Initial state\n  expect(screen.getByText('Content A')).toBeVisible();\n  expect(screen.queryByText('Content B')).not.toBeVisible();\n\n  \u002F\u002F Interact and assert\n  await userEvent.click(screen.getByRole('button', { name: 'Tab B' }));\n  expect(screen.getByText('Content B')).toBeVisible();\n});\n```\n\nFor controlled compound components, test that `onChange` is called with the correct\nvalue and that the displayed state matches the controlled `value` prop.\n\n**Rule of thumb:** Test behavior (what the user sees and can do), not implementation\n(which Context value changed); this keeps tests resilient to internal refactors.\n",{"id":103,"difficulty":95,"q":104,"a":105},"performance-concerns","What performance concerns exist with Context-based compound components and how do you address them?","Every consumer of a Context re-renders whenever the **entire Context value changes**.\nIf the parent passes a new object reference on every render (even if the values are the\nsame), all sub-components re-render unnecessarily.\n\n```jsx\n\u002F\u002F Problem: new object reference on every render\nfunction Tabs({ children }) {\n  const [active, setActive] = useState('a');\n  return (\n    \u003CTabsCtx.Provider value={{ active, setActive }}> {\u002F* new ref each time *\u002F}\n      {children}\n    \u003C\u002FTabsCtx.Provider>\n  );\n}\n\n\u002F\u002F Fix 1: useMemo to stabilize the context object\nfunction Tabs({ children }) {\n  const [active, setActive] = useState('a');\n  const ctx = useMemo(() => ({ active, setActive }), [active]);\n  return \u003CTabsCtx.Provider value={ctx}>{children}\u003C\u002FTabsCtx.Provider>;\n}\n\n\u002F\u002F Fix 2: split into separate contexts (state vs dispatch)\nconst TabsStateCtx    = createContext(null); \u002F\u002F triggers re-render on change\nconst TabsDispatchCtx = createContext(null); \u002F\u002F stable — setActive never changes\n```\n\nSplitting into a state context and a dispatch context is the most effective approach:\ncomponents that only call `setActive` (like `Tabs.Tab`) subscribe to `TabsDispatchCtx`\nand never re-render when the active value changes.\n\n**Rule of thumb:** Start with a single merged Context; split into state + dispatch only\nwhen profiling confirms unnecessary re-renders are a real bottleneck.\n",{"id":107,"difficulty":95,"q":108,"a":109},"server-components-limitation","How does the React Server Components model affect compound components that use Context?","**React Server Components (RSC)** cannot use Context — `createContext` and `useContext`\nare client-only APIs. This means compound components that rely on Context must be\n**client components** (marked `'use client'`).\n\nThe practical implication is a **client boundary** at the compound component root:\n\n```tsx\n\u002F\u002F tabs.tsx — must be a client component\n'use client';\nimport { createContext, useContext, useState } from 'react';\n\u002F\u002F ... full compound component implementation\n\n\u002F\u002F page.tsx — server component; Tabs forces a client subtree\nimport Tabs from '.\u002Ftabs';\n\nexport default function Page() {\n  return (\n    \u002F\u002F Everything inside \u003CTabs> runs on the client\n    \u003CTabs defaultValue=\"a\">\n      \u003CTabs.Tab value=\"a\">A\u003C\u002FTabs.Tab>\n      \u003CTabs.Panel value=\"a\">\n        {\u002F* Server components can be passed as children to client components *\u002F}\n        \u003CServerDataTable \u002F>\n      \u003C\u002FTabs.Panel>\n    \u003C\u002FTabs>\n  );\n}\n```\n\nYou can still pass **server-rendered content as children** into a client compound\ncomponent — RSC allows server components to be children of client components. The\nserver component renders its output and passes it as serialized props.\n\n**Rule of thumb:** Mark the compound root (and sub-components that use Context) as\n`'use client'`; keep the data-fetching server components as their consumers' children\nrather than embedding them inside the compound component module.\n",{"id":111,"difficulty":34,"q":112,"a":113},"vs-render-props","How do compound components compare to render props as a composition pattern?","Both patterns share state with consumers, but they differ in where the consumer\ninteracts with that state.\n\n**Render props** — the consumer receives state as function arguments and can use it\nanywhere within the callback, including conditional logic. More explicit and flexible,\nbut produces deeply indented JSX (\"callback hell\").\n\n**Compound components** — state is accessed implicitly inside sub-components via Context.\nProduces flat, declarative JSX that reads like HTML.\n\n```jsx\n\u002F\u002F Render props: state is explicit, layout is free-form\n\u003CTabs>\n  {({ active, setActive }) => (\n    \u003Cdiv className=\"custom-layout\">\n      \u003Cbutton onClick={() => setActive('a')}\n        style={{ fontWeight: active === 'a' ? 'bold' : 'normal' }}>A\u003C\u002Fbutton>\n      {active === 'a' && \u003Cdiv>Panel A\u003C\u002Fdiv>}\n    \u003C\u002Fdiv>\n  )}\n\u003C\u002FTabs>\n\n\u002F\u002F Compound: declarative, less flexible but cleaner\n\u003CTabs defaultValue=\"a\">\n  \u003CTabs.Tab value=\"a\">A\u003C\u002FTabs.Tab>\n  \u003CTabs.Panel value=\"a\">Panel A\u003C\u002FTabs.Panel>\n\u003C\u002FTabs>\n```\n\n**Rule of thumb:** Prefer compound components for design-system UI widgets where layout\nflexibility is bounded; prefer render props when consumers need the raw state to drive\narbitrary custom logic.\n",{"id":115,"difficulty":95,"q":116,"a":117},"accessibility-in-compound","How do you handle ARIA attributes in compound components to ensure accessibility?","Compound components should **generate and wire ARIA attributes automatically** so\nconsumers don't need to add them manually. The Context provides stable IDs and\nexpanded\u002Fselected state that sub-components apply to their DOM elements.\n\n```jsx\nfunction Tabs({ defaultValue, id: baseId = useId(), children }) {\n  const [active, setActive] = useState(defaultValue);\n  return (\n    \u003CTabsCtx.Provider value={{ active, setActive, baseId }}>\n      {children}\n    \u003C\u002FTabsCtx.Provider>\n  );\n}\n\nTabs.Tab = function TabsTab({ value, children }) {\n  const { active, setActive, baseId } = useTabs();\n  return (\n    \u003Cbutton\n      id={`${baseId}-tab-${value}`}       \u002F\u002F stable ID\n      role=\"tab\"\n      aria-selected={active === value}\n      aria-controls={`${baseId}-panel-${value}`} \u002F\u002F links to panel\n      onClick={() => setActive(value)}\n    >\n      {children}\n    \u003C\u002Fbutton>\n  );\n};\n\nTabs.Panel = function TabsPanel({ value, children }) {\n  const { active, baseId } = useTabs();\n  return (\n    \u003Cdiv\n      id={`${baseId}-panel-${value}`}     \u002F\u002F matches aria-controls\n      role=\"tabpanel\"\n      aria-labelledby={`${baseId}-tab-${value}`}\n      hidden={active !== value}\n    >\n      {children}\n    \u003C\u002Fdiv>\n  );\n};\n```\n\n**Rule of thumb:** Generate IDs with `useId()` inside the root component and share them\nvia Context so `aria-controls`\u002F`aria-labelledby` pairs are always consistent without\nrequiring consumers to manage IDs manually.\n",19,null,{"description":32},"React compound components interview questions — implicit state sharing, Context-based APIs, flexible composition, and component slot patterns.","react\u002Fpatterns\u002Fcompound-components","2026-06-24","TLvrPCxxzntq3ZbMDXCJk4oBf_smSWVPIoVgZQ_K2G0",{"id":126,"title":127,"body":128,"description":32,"difficulty":34,"extension":35,"framework":10,"frameworkSlug":8,"meta":132,"navigation":37,"order":11,"path":133,"questions":134,"questionsCount":118,"related":119,"seo":211,"seoDescription":212,"stem":213,"subtopic":214,"topic":19,"topicSlug":21,"updated":123,"__hash__":215},"qa\u002Freact\u002Fpatterns\u002Frender-props-hoc.md","Render Props Hoc",{"type":29,"value":129,"toc":130},[],{"title":32,"searchDepth":11,"depth":11,"links":131},[],{},"\u002Freact\u002Fpatterns\u002Frender-props-hoc",[135,139,143,147,151,155,159,163,167,171,175,179,183,187,191,195,199,203,207],{"id":136,"difficulty":42,"q":137,"a":138},"what-is-render-props-pattern","What is the render props pattern and what problem does it solve?","The **render props** pattern is a technique for sharing stateful logic between components\nby passing a **function as a prop**. The host component manages state and calls that\nfunction with the state as arguments, letting the consumer decide what to render.\n\nThe problem it solves is **logic reuse without inheritance**. Before hooks, if two\ncomponents needed the same piece of state (mouse position, window size, data fetching\nstatus) you had three options: copy-paste the logic, lift state up (coupling unrelated\ncomponents), or use render props \u002F HOCs. Render props kept the logic encapsulated in\none place while giving the consumer full rendering control.\n\n```jsx\n\u002F\u002F DataFetcher owns fetching logic; caller decides the UI\nfunction DataFetcher({ url, render }) {\n  const [data, setData] = React.useState(null);\n  const [loading, setLoading] = React.useState(true);\n\n  React.useEffect(() => {\n    fetch(url)\n      .then(r => r.json())\n      .then(d => { setData(d); setLoading(false); });\n  }, [url]);\n\n  \u002F\u002F Delegates rendering entirely to the caller\n  return render({ data, loading });\n}\n\n\u002F\u002F Usage — caller controls the UI\n\u003CDataFetcher\n  url=\"\u002Fapi\u002Fusers\"\n  render={({ data, loading }) =>\n    loading ? \u003CSpinner \u002F> : \u003CUserList users={data} \u002F>\n  }\n\u002F>\n```\n\n**Rule of thumb:** Render props shine when you want to share complex stateful behaviour\nwhile letting each consumer render something different.\n",{"id":140,"difficulty":42,"q":141,"a":142},"function-as-child-vs-render-prop","What is the function-as-child pattern and how does it differ from an explicit render prop?","**Function-as-child** (also called \"children as a function\") is just a render prop\nwhere the prop name is `children` instead of a custom name like `render`. The component\ncalls `props.children(...)` exactly as it would call `props.render(...)`.\n\nThe only differences are:\n- Syntactic: the function lives inside the JSX tag body, which reads more naturally\n  for simple cases.\n- Discoverability: explicit render props (`render`, `renderHeader`, etc.) are visible\n  in prop-types\u002FTypeScript signatures; `children` can surprise readers if they expect\n  a ReactNode.\n\n```jsx\n\u002F\u002F Explicit render prop\n\u003CMouse render={({ x, y }) => \u003CCursor x={x} y={y} \u002F>} \u002F>\n\n\u002F\u002F Function-as-child — identical behaviour, different syntax\n\u003CMouse>\n  {({ x, y }) => \u003CCursor x={x} y={y} \u002F>}\n\u003C\u002FMouse>\n\n\u002F\u002F Inside Mouse — both approaches call the same way\nfunction Mouse({ children }) {\n  const [pos, setPos] = React.useState({ x: 0, y: 0 });\n  return (\n    \u003Cdiv onMouseMove={e => setPos({ x: e.clientX, y: e.clientY })}>\n      {children(pos)}  {\u002F* or props.render(pos) *\u002F}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n**Rule of thumb:** Use an explicit render prop when you need multiple render slots\n(`renderHeader`, `renderFooter`); use `children` when there is only one slot and\nthe JSX nesting reads naturally.\n",{"id":144,"difficulty":42,"q":145,"a":146},"what-is-hoc","What is a Higher-Order Component (HOC) and what is its signature?","A **Higher-Order Component** is a function that takes a component and returns a new,\nenhanced component. It is the React adaptation of the higher-order function concept —\njust as `Array.map` takes a function and returns a new array, an HOC takes a component\nand returns a component.\n\nThe canonical signature is:\n\n```ts\n\u002F\u002F Generic signature: WrappedComponent in, EnhancedComponent out\nfunction withSomething\u003CP extends object>(\n  WrappedComponent: React.ComponentType\u003CP>\n): React.ComponentType\u003CP & InjectedProps> {\n\n  function WithSomething(props: P) {\n    const injected = useSomethingLogic(); \u002F\u002F HOC-owned logic\n    return \u003CWrappedComponent {...props} {...injected} \u002F>;\n  }\n\n  \u002F\u002F Naming convention: prefix with \"with\"\n  WithSomething.displayName =\n    `WithSomething(${WrappedComponent.displayName ?? WrappedComponent.name ?? 'Component'})`;\n\n  return WithSomething;\n}\n```\n\nKey points:\n- The **naming convention** is `withXxx` (camelCase, \"with\" prefix) — e.g., `withAuth`,\n  `withTheme`, `withLogger`.\n- Set `displayName` so React DevTools shows `WithAuth(Dashboard)` rather than an\n  anonymous component.\n- The HOC **does not mutate** the wrapped component; it wraps it.\n\n**Rule of thumb:** If a function takes a component and returns a component, it is an\nHOC; name it `withXxx` and set `displayName`.\n",{"id":148,"difficulty":34,"q":149,"a":150},"hoc-composition","How do you compose multiple HOCs and what utility makes that cleaner?","You can nest HOC calls directly, but deep nesting reads inside-out and is hard to\nmaintain. The standard solution is a **`compose` utility** (available in lodash, Redux,\nRamda, or trivial to write) that applies functions right-to-left so the reading order\nmatches the wrapping order.\n\n```js\n\u002F\u002F Naive nesting — reads inside-out, breaks easily when reordering\nexport default withLogger(withAuth(withTheme(MyComponent)));\n\n\u002F\u002F compose applies right-to-left: theme → auth → logger (outermost last)\nimport { compose } from 'redux'; \u002F\u002F or lodash\u002Ffp\n\nconst enhance = compose(\n  withLogger,   \u002F\u002F applied last (outermost)\n  withAuth,     \u002F\u002F applied second\n  withTheme,    \u002F\u002F applied first (innermost, closest to component)\n);\n\nexport default enhance(MyComponent);\n\n\u002F\u002F Minimal compose implementation for reference\nconst compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);\n```\n\nOrder matters: the outermost HOC's props arrive first. If `withAuth` reads a `theme`\nprop injected by `withTheme`, then `withTheme` must be applied before `withAuth`\n(listed after it in `compose`).\n\n**Rule of thumb:** Use `compose` when stacking three or more HOCs; keep the list in\ninside-out (most-specific-first) order so execution matches your mental model.\n",{"id":152,"difficulty":34,"q":153,"a":154},"cross-cutting-concerns-hoc","Name three cross-cutting concerns that HOCs handle well and explain one in detail.","Classic cross-cutting concerns suited to HOCs:\n\n1. **Authentication \u002F authorisation guards** — redirect unauthenticated users before\n   rendering a page component.\n2. **Analytics \u002F logging** — record component mount, unmount, and prop changes without\n   touching business logic components.\n3. **Error boundaries** — wrap any component with standardised error UI.\n\n`withAuth` example in detail:\n\n```jsx\n\u002F\u002F withAuth.jsx — auth guard HOC\nimport { Navigate } from 'react-router-dom';\nimport { useAuth } from '..\u002Fcontext\u002FAuthContext';\n\nfunction withAuth(WrappedComponent, requiredRole = null) {\n  function WithAuth(props) {\n    const { user, loading } = useAuth();\n\n    if (loading) return \u003CSpinner \u002F>;\n    if (!user) return \u003CNavigate to=\"\u002Flogin\" replace \u002F>;\n    if (requiredRole && user.role !== requiredRole)\n      return \u003CNavigate to=\"\u002Fforbidden\" replace \u002F>;\n\n    \u002F\u002F User is authenticated (and has the right role) — render component\n    return \u003CWrappedComponent {...props} \u002F>;\n  }\n\n  WithAuth.displayName = `WithAuth(${WrappedComponent.displayName ?? WrappedComponent.name})`;\n  return WithAuth;\n}\n\n\u002F\u002F Usage\nexport default withAuth(AdminDashboard, 'admin');\n```\n\n**Rule of thumb:** HOCs are ideal for cross-cutting concerns that need to intercept\nrendering (guards, error boundaries) or observe lifecycle events (logging) without\naltering the wrapped component's own logic.\n",{"id":156,"difficulty":34,"q":157,"a":158},"prop-collision-hoc","What is prop collision in HOCs and how do you prevent it?","**Prop collision** occurs when an HOC injects a prop whose name clashes with a prop\nthe wrapped component (or a parent) already uses. The HOC's value silently wins because\nit is spread last (or first), overwriting the intended value and causing subtle bugs.\n\nPrevention strategies:\n\n```jsx\n\u002F\u002F BAD — HOC spreads injected props after ownProps; \"user\" collision\nfunction withUser(WrappedComponent) {\n  return function(props) {\n    const user = useCurrentUser();\n    \u002F\u002F If parent passes user={guestUser}, HOC's user overwrites it silently\n    return \u003CWrappedComponent {...props} user={user} \u002F>;\n  };\n}\n\n\u002F\u002F GOOD — namespace injected props under a dedicated key\nfunction withUser(WrappedComponent) {\n  return function({ injectedUser, ...ownProps }) {\n    const user = useCurrentUser();\n    \u002F\u002F Injected prop has a unique name; no risk of shadowing parent props\n    return \u003CWrappedComponent {...ownProps} currentUser={user} \u002F>;\n  };\n}\n\n\u002F\u002F BEST — use TypeScript to make the contract explicit\ntype WithUserProps = { currentUser: User };\nfunction withUser\u003CP extends WithUserProps>(\n  WrappedComponent: React.ComponentType\u003CP>\n) { \u002F* ... *\u002F }\n```\n\nOther strategies: document all injected prop names, prefix them (`_injectedUser`),\nor prefer hooks (which do not pollute the prop namespace at all).\n\n**Rule of thumb:** Never spread HOC-injected props with generic names; use descriptive,\nnamespaced names and make them explicit in TypeScript types.\n",{"id":160,"difficulty":34,"q":161,"a":162},"why-hooks-replaced-render-props-hocs","Why did custom hooks largely replace render props and HOCs?","Custom hooks solve the same logic-reuse problem without the downsides of both patterns:\n\n| Issue | Render props \u002F HOCs | Custom hooks |\n|---|---|---|\n| **Extra DOM nodes** | Yes — every HOC \u002F render-prop host adds a wrapper in the tree | No — hooks run inside the calling component |\n| **Prop drilling \u002F collision** | HOCs inject props that can clash | Hooks return values via destructuring — no prop namespace |\n| **Composability** | HOCs compose left-to-right but reading order is confusing | Just call multiple hooks sequentially |\n| **TypeScript** | Generics + conditional types needed for good inference | Plain function return types — straightforward |\n| **DevTools clarity** | Deep \"wrapper hell\" in component tree | Flat component tree |\n\n```jsx\n\u002F\u002F Pre-hooks: render prop for mouse position\n\u003CMouseTracker render={({ x, y }) => \u003CCrosshair x={x} y={y} \u002F>} \u002F>\n\n\u002F\u002F Post-hooks: extract into a custom hook — same logic, no wrapper\nfunction useMousePosition() {\n  const [pos, setPos] = React.useState({ x: 0, y: 0 });\n  React.useEffect(() => {\n    const handler = e => setPos({ x: e.clientX, y: e.clientY });\n    window.addEventListener('mousemove', handler);\n    return () => window.removeEventListener('mousemove', handler);\n  }, []);\n  return pos;\n}\n\nfunction Crosshair() {\n  const { x, y } = useMousePosition(); \u002F\u002F clean, no wrapper\n  return \u003Cdiv style={{ top: y, left: x }} \u002F>;\n}\n```\n\n**Rule of thumb:** Reach for a custom hook first; only use render props or HOCs when\nyou need to control rendering structure (render prop) or integrate with class components\nor third-party code that cannot use hooks (HOC).\n",{"id":164,"difficulty":34,"q":165,"a":166},"when-render-props-still-right-tool","When are render props still the right tool even in a hooks world?","Render props remain the best choice in several scenarios:\n\n1. **Controlled render delegation** — when the parent needs to decide *what* renders\n   inside a complex host (e.g., a virtualised list that injects row index\u002Fstyle and\n   expects the caller to return the row JSX).\n2. **Class component consumers** — hooks cannot run inside class components; an HOC\n   or render-prop component is the only way to feed hook-based logic into them.\n3. **Library APIs** — `react-router` (`\u003CRoute render>` in v5), `formik` (`\u003CField>`),\n   and `react-window` (`\u003CFixedSizeList>`) expose render props because they cannot\n   know your render tree ahead of time.\n\n```jsx\n\u002F\u002F react-window — render prop is the correct API; hooks cannot replace it here\nimport { FixedSizeList } from 'react-window';\n\nfunction VirtualList({ items }) {\n  const Row = ({ index, style }) => (\n    \u002F\u002F style MUST be applied for virtualisation to work\n    \u003Cdiv style={style}>{items[index].name}\u003C\u002Fdiv>\n  );\n\n  return (\n    \u003CFixedSizeList height={400} itemCount={items.length} itemSize={35} width=\"100%\">\n      {Row}\n    \u003C\u002FFixedSizeList>\n  );\n}\n```\n\n**Rule of thumb:** Render props are still the right tool when a library needs you to\nsupply a JSX factory, or when the component consuming your logic is a class component.\n",{"id":168,"difficulty":95,"q":169,"a":170},"static-methods-hocs","Why do HOCs lose static methods from the wrapped component and how do you fix it?","A wrapped component's **static methods** (e.g., `getLayout`, `fetchData`,\n`propTypes`) are defined on the original component object. The HOC returns a *new*\nfunction object that does not automatically copy those statics, so callers that\nlook up `EnhancedComponent.getLayout` find `undefined`.\n\nThe fix is **`hoist-non-react-statics`**, a small utility that copies all non-React\nstatics from the wrapped component to the wrapper:\n\n```jsx\nimport hoistNonReactStatics from 'hoist-non-react-statics';\n\nfunction withLogger(WrappedComponent) {\n  function WithLogger(props) {\n    React.useEffect(() => { console.log('mounted'); }, []);\n    return \u003CWrappedComponent {...props} \u002F>;\n  }\n\n  WithLogger.displayName =\n    `WithLogger(${WrappedComponent.displayName ?? WrappedComponent.name})`;\n\n  \u002F\u002F Copy getLayout, fetchData, propTypes, etc. from original\n  hoistNonReactStatics(WithLogger, WrappedComponent);\n\n  return WithLogger;\n}\n\n\u002F\u002F Statics survive the wrapping\nWithLogger.getLayout === WrappedComponent.getLayout; \u002F\u002F true\n```\n\nReact-specific statics (`defaultProps`, `propTypes`, `contextType`, `displayName`,\n`getDerivedStateFromProps`, etc.) are intentionally **not** hoisted — the library\nhas a hardcoded exclusion list for them.\n\n**Rule of thumb:** Always call `hoistNonReactStatics(Wrapper, WrappedComponent)`\ninside every HOC factory so page-level statics (especially Next.js `getLayout`) are\nnot silently dropped.\n",{"id":172,"difficulty":95,"q":173,"a":174},"forwardref-in-hocs","How do you forward refs through a HOC?","HOCs break `ref` forwarding by default because `ref` is not a real prop — it is\nhandled by React's reconciler and does not appear in `props`. A ref attached to\nthe HOC wrapper points at the wrapper, not the underlying DOM node or component.\n\nThe fix is `React.forwardRef`:\n\n```jsx\nfunction withFocusRing(WrappedComponent) {\n  \u002F\u002F forwardRef creates a component that passes its ref down\n  const WithFocusRing = React.forwardRef(function(props, ref) {\n    const [focused, setFocused] = React.useState(false);\n    return (\n      \u003Cdiv className={focused ? 'ring' : ''}>\n        \u003CWrappedComponent\n          {...props}\n          ref={ref}           \u002F\u002F forward the ref to the real component\n          onFocus={() => setFocused(true)}\n          onBlur={() => setFocused(false)}\n        \u002F>\n      \u003C\u002Fdiv>\n    );\n  });\n\n  WithFocusRing.displayName =\n    `WithFocusRing(${WrappedComponent.displayName ?? WrappedComponent.name})`;\n\n  hoistNonReactStatics(WithFocusRing, WrappedComponent);\n  return WithFocusRing;\n}\n\n\u002F\u002F Caller gets a ref to the real input, not the wrapper div\nconst EnhancedInput = withFocusRing(React.forwardRef((props, ref) =>\n  \u003Cinput ref={ref} {...props} \u002F>\n));\nconst ref = React.createRef();\n\u003CEnhancedInput ref={ref} \u002F>;\n```\n\n**Rule of thumb:** Wrap the inner component in `React.forwardRef` and thread the\n`ref` argument through to `WrappedComponent`; always pair this with `hoistNonReactStatics`.\n",{"id":176,"difficulty":34,"q":177,"a":178},"hoc-performance-implications","What are the performance implications of HOCs and render props?","Both patterns can introduce unnecessary re-renders if not handled carefully.\n\n**HOC issues:**\n- Each HOC in a composition chain is a separate React component — `React.memo` on\n  the inner component does not prevent the wrapper from re-rendering.\n- If the HOC creates a new object or function on every render and passes it as a\n  prop, the wrapped component will see a new reference and re-render even if the\n  underlying data did not change.\n\n**Render prop issues (the classic \"always re-renders\" problem):**\n```jsx\n\u002F\u002F BAD — inline arrow function creates a new function reference every render\n\u002F\u002F → Mouse re-renders, calls render(), child always re-renders\n\u003CMouse render={({ x, y }) => \u003CCrosshair x={x} y={y} \u002F>} \u002F>\n\n\u002F\u002F GOOD — stable function reference with useCallback (or define outside render)\nfunction App() {\n  const renderCrosshair = React.useCallback(\n    ({ x, y }) => \u003CCrosshair x={x} y={y} \u002F>,\n    [] \u002F\u002F stable — no deps\n  );\n  return \u003CMouse render={renderCrosshair} \u002F>;\n}\n```\n\nFor HOCs, apply `React.memo` to *each layer* independently, or memoize injected\nvalues inside the HOC with `useMemo`\u002F`useCallback`.\n\n**Rule of thumb:** Stabilise function references passed as render props with\n`useCallback`; inside HOCs, memoize injected values to avoid cascading re-renders.\n",{"id":180,"difficulty":95,"q":181,"a":182},"typescript-generics-hoc","How do you type a HOC in TypeScript so that the wrapped component's props are preserved?","The key is using **generics** to capture the wrapped component's prop type and subtract\nthe injected props so callers do not have to re-supply them.\n\n```tsx\n\u002F\u002F Props injected by the HOC\ninterface WithAuthProps {\n  currentUser: User;\n}\n\n\u002F\u002F P = full props of wrapped component\n\u002F\u002F We subtract WithAuthProps so callers don't pass currentUser manually\nfunction withAuth\u003CP extends WithAuthProps>(\n  WrappedComponent: React.ComponentType\u003CP>\n): React.ComponentType\u003COmit\u003CP, keyof WithAuthProps>> {\n\n  function WithAuth(props: Omit\u003CP, keyof WithAuthProps>) {\n    const { user } = useAuth();\n    if (!user) return \u003CNavigate to=\"\u002Flogin\" replace \u002F>;\n\n    \u002F\u002F Cast needed because TS can't fully verify the Omit + spread\n    return \u003CWrappedComponent {...(props as P)} currentUser={user} \u002F>;\n  }\n\n  WithAuth.displayName =\n    `WithAuth(${WrappedComponent.displayName ?? WrappedComponent.name ?? 'Component'})`;\n\n  hoistNonReactStatics(WithAuth, WrappedComponent);\n  return WithAuth;\n}\n\n\u002F\u002F Usage — TypeScript knows currentUser is supplied by HOC, not by caller\ninterface DashboardProps extends WithAuthProps { title: string; }\nfunction Dashboard({ currentUser, title }: DashboardProps) { \u002F* ... *\u002F }\n\nconst ProtectedDashboard = withAuth(Dashboard);\n\u003CProtectedDashboard title=\"Home\" \u002F> \u002F\u002F ✓ — no currentUser required\n```\n\n**Rule of thumb:** Use `P extends InjectedProps` on the generic and `Omit\u003CP, keyof InjectedProps>`\non the output type so the HOC's additions are invisible to callers.\n",{"id":184,"difficulty":34,"q":185,"a":186},"testing-hoc-wrapped-components","What are two strategies for testing a HOC-wrapped component?","**Strategy 1 — Test the wrapped component in isolation.**\nExport the unwrapped component as a named export alongside the default HOC-wrapped\nexport. In tests, import the unwrapped version and pass the injected props manually.\nThis keeps unit tests free of HOC side-effects.\n\n**Strategy 2 — Mock the HOC's dependencies and test the full composed component.**\nUseful for integration tests that need to verify the HOC's interception logic (e.g.,\nthat `withAuth` redirects unauthenticated users).\n\n```tsx\n\u002F\u002F userList.tsx — dual export pattern\nexport function UserList({ currentUser }: WithAuthProps & { currentUser: User }) {\n  return \u003Cdiv>{currentUser.name}\u003C\u002Fdiv>;\n}\nexport default withAuth(UserList); \u002F\u002F default = enhanced\n\n\u002F\u002F userList.test.tsx\nimport { UserList } from '.\u002FuserList'; \u002F\u002F named — no HOC\nimport { render, screen } from '@testing-library\u002Freact';\n\ntest('renders user name', () => {\n  render(\u003CUserList currentUser={{ name: 'Alice', role: 'user' }} \u002F>);\n  expect(screen.getByText('Alice')).toBeInTheDocument();\n});\n\n\u002F\u002F Integration test — mock auth context\nimport WrappedUserList from '.\u002FuserList'; \u002F\u002F default — HOC included\ntest('redirects when unauthenticated', () => {\n  mockUseAuth({ user: null, loading: false });\n  render(\u003CWrappedUserList \u002F>, { wrapper: MemoryRouterWrapper });\n  expect(mockNavigate).toHaveBeenCalledWith('\u002Flogin', expect.anything());\n});\n```\n\n**Rule of thumb:** Always export the base component as a named export so unit tests\ncan bypass the HOC; use integration tests only when you need to test the HOC's own\nbehaviour.\n",{"id":188,"difficulty":42,"q":189,"a":190},"render-props-vs-hoc-choice","When would you choose a render prop over a HOC, and vice-versa?","The decision hinges on who controls the rendered output and how the logic is consumed.\n\n| Choose **render prop** when… | Choose **HOC** when… |\n|---|---|\n| The consumer needs to render different UI per use-site | Every consumer renders roughly the same structure |\n| You want explicit, visible data flow in JSX | You want transparent wrapping (consumer doesn't change) |\n| You need to compose render slots (header, body, footer) | You need to decorate a whole page\u002Froute component |\n| The consuming component is a function component | You need to wrap class components with consistent behaviour |\n\n```jsx\n\u002F\u002F Render prop — consumer decides the UI\n\u003CToggle>\n  {({ on, toggle }) =>\n    on\n      ? \u003CButton onClick={toggle}>Turn Off\u003C\u002FButton>\n      : \u003CButton onClick={toggle}>Turn On\u003C\u002FButton>\n  }\n\u003C\u002FToggle>\n\n\u002F\u002F HOC — consumer is unaware of the wrapping\nconst AnalyticsButton = withPageViewLogger(Button);\n\u002F\u002F Button code is unchanged; analytics are injected invisibly\n\u003CAnalyticsButton onClick={handleClick}>Buy Now\u003C\u002FAnalyticsButton>\n```\n\n**Rule of thumb:** Use render props when the consumer owns the output markup; use\nHOCs when you want to transparently add behaviour to an existing component.\n",{"id":192,"difficulty":42,"q":193,"a":194},"wrapper-hell","What is \"wrapper hell\" and how do you recognise it in React DevTools?","**Wrapper hell** (also called \"HOC hell\" or \"pyramid of doom\") describes a component\ntree where many HOC layers surround a single component, making DevTools output nearly\nunreadable and stack traces hard to follow.\n\nIn React DevTools you see something like:\n\n```\n\u002F\u002F Component tree with 5 HOCs — hard to navigate\n\u003CWithRouter>\n  \u003CWithTheme>\n    \u003CWithAuth>\n      \u003CWithLogger>\n        \u003CWithErrorBoundary>\n          \u003CDashboard \u002F>\n        \u003C\u002FWithErrorBoundary>\n      \u003C\u002FWithLogger>\n    \u003C\u002FWithAuth>\n  \u003C\u002FWithTheme>\n\u003C\u002FWithRouter>\n```\n\nSolutions:\n1. **Replace with hooks** — collapse all five wrappers into hook calls inside `Dashboard`.\n2. **Use `compose`** — at least the source code reads linearly even if the tree is deep.\n3. **Set meaningful `displayName`** on each HOC so DevTools shows `WithAuth(Dashboard)`.\n\n```jsx\n\u002F\u002F After refactoring to hooks — flat tree, same logic\nfunction Dashboard() {\n  const { params } = useRouter();\n  const theme = useTheme();\n  const { user } = useAuth();\n  usePageLogger();\n  useErrorBoundary();\n  \u002F\u002F ...\n}\n```\n\n**Rule of thumb:** If DevTools shows more than two or three wrapper components around\na single leaf, consider collapsing the HOC stack into custom hooks.\n",{"id":196,"difficulty":34,"q":197,"a":198},"hoc-vs-hooks-class-components","Can hooks fully replace HOCs for class components? What is the recommended migration path?","**No** — hooks cannot run inside class components. An HOC (or render prop) remains\nthe only way to inject hook-based logic into a class component. This matters for\nlegacy codebases or third-party libraries still using class components.\n\nThe recommended migration path is **incremental**:\n\n```jsx\n\u002F\u002F Step 1 — write the logic as a hook\nfunction useTheme() {\n  return React.useContext(ThemeContext);\n}\n\n\u002F\u002F Step 2 — create a thin HOC that calls the hook and injects the result\n\u002F\u002F           This bridges class components without rewriting them\nfunction withTheme(WrappedComponent) {\n  function WithTheme(props) {\n    const theme = useTheme(); \u002F\u002F hook runs here (function component)\n    return \u003CWrappedComponent {...props} theme={theme} \u002F>;\n  }\n  WithTheme.displayName = `WithTheme(${WrappedComponent.name})`;\n  return WithTheme;\n}\n\n\u002F\u002F Step 3 — class component uses the HOC today\nclass Toolbar extends React.Component {\n  render() {\n    return \u003Cdiv style={{ background: this.props.theme.bg }}>…\u003C\u002Fdiv>;\n  }\n}\nexport default withTheme(Toolbar);\n\n\u002F\u002F Step 4 — when Toolbar is converted to a function component, drop the HOC\n\u002F\u002F           and call useTheme() directly\n```\n\n**Rule of thumb:** Write all new logic as hooks; wrap in a thin HOC only to bridge\nclass components; remove the HOC shim when the class component is converted.\n",{"id":200,"difficulty":42,"q":201,"a":202},"hoc-display-name-convention","Why is setting displayName on a HOC important and what is the correct format?","React uses `displayName` (or the function name as a fallback) when rendering component\ntrees in **DevTools** and in **error stack traces**. Without it, every HOC-wrapped\ncomponent shows as `Anonymous` or just the HOC function name, making debugging very\nhard when multiple HOCs are stacked.\n\nThe standard format is `WithXxx(OriginalName)`:\n\n```jsx\nfunction withSubscription(WrappedComponent) {\n  function WithSubscription(props) {\n    \u002F\u002F ...\n    return \u003CWrappedComponent {...props} \u002F>;\n  }\n\n  \u002F\u002F Correct format: WithHocName(WrappedName)\n  WithSubscription.displayName =\n    `WithSubscription(${\n      WrappedComponent.displayName  \u002F\u002F already set display name\n      ?? WrappedComponent.name      \u002F\u002F function\u002Fclass name\n      ?? 'Component'               \u002F\u002F last resort fallback\n    })`;\n\n  return WithSubscription;\n}\n\n\u002F\u002F DevTools now shows: WithSubscription(Dashboard)\n\u002F\u002F instead of:         WithSubscription or Anonymous\n```\n\nSome teams use a `getDisplayName` helper to deduplicate the ternary chain across\nall HOCs in a codebase.\n\n**Rule of thumb:** Always set `displayName` using the `WithXxx(InnerName)` format;\ncheck all three sources (`displayName`, `name`, fallback) in that priority order.\n",{"id":204,"difficulty":95,"q":205,"a":206},"render-props-error-boundaries","Can you use render props with error boundaries? How?","Yes. An **error boundary** must be a class component (React's `componentDidCatch`\nAPI is not yet available as a hook), but you can expose its caught error via a\nrender prop so the caller controls the fallback UI — combining the two patterns.\n\n```jsx\nclass ErrorBoundary extends React.Component {\n  state = { error: null };\n\n  static getDerivedStateFromError(error) {\n    return { error };\n  }\n\n  componentDidCatch(error, info) {\n    reportError(error, info); \u002F\u002F side-effect: logging service\n  }\n\n  render() {\n    const { error } = this.state;\n    const { children, fallback } = this.props;\n\n    if (error) {\n      \u002F\u002F Delegate fallback UI to the caller via render prop\n      return typeof fallback === 'function'\n        ? fallback(error)       \u002F\u002F render prop form\n        : fallback ?? \u003Cp>Something went wrong.\u003C\u002Fp>;\n    }\n\n    return children;\n  }\n}\n\n\u002F\u002F Caller controls the fallback UI\n\u003CErrorBoundary fallback={err => \u003CErrorPage message={err.message} \u002F>}>\n  \u003CUserProfile userId={id} \u002F>\n\u003C\u002FErrorBoundary>\n```\n\nThis pattern is exactly how the popular `react-error-boundary` library works\ninternally (`renderError` \u002F `FallbackComponent` prop).\n\n**Rule of thumb:** Error boundary logic stays in a class component; expose the\nfallback slot as a render prop so each call site can render appropriate recovery UI.\n",{"id":208,"difficulty":95,"q":209,"a":210},"render-prop-pure-component-issue","Why can inline render prop functions cause issues with PureComponent or React.memo and how do you fix it?","`React.PureComponent` and `React.memo` perform a **shallow comparison** of props.\nAn inline arrow function creates a new function object on every parent render, so\nthe render-prop component always sees a changed `render` prop — the shallow compare\nfails, PureComponent's optimisation is bypassed, and the component re-renders\nunconditionally.\n\n```jsx\nclass Mouse extends React.PureComponent {\n  \u002F\u002F shallow compare on props.render — always a new reference → always re-renders\n  render() { return this.props.render(this.state); }\n}\n\n\u002F\u002F BAD — new arrow function on every render of App\nclass App extends React.Component {\n  render() {\n    return \u003CMouse render={pos => \u003CCat {...pos} \u002F>} \u002F>;  \u002F\u002F new fn each time!\n  }\n}\n\n\u002F\u002F GOOD — define the render function as an instance method; reference is stable\nclass App extends React.Component {\n  renderCat = pos => \u003CCat {...pos} \u002F>;  \u002F\u002F stable class field\n\n  render() {\n    return \u003CMouse render={this.renderCat} \u002F>;\n  }\n}\n\n\u002F\u002F GOOD (function component equivalent) — useCallback for stable reference\nfunction App() {\n  const renderCat = React.useCallback(pos => \u003CCat {...pos} \u002F>, []);\n  return \u003CMouse render={renderCat} \u002F>;\n}\n```\n\n**Rule of thumb:** Never pass an inline arrow function as a render prop to a\n`PureComponent` or `memo`-wrapped component; stabilise the reference with\n`useCallback` or a class instance method.\n",{"description":32},"React render props and HOC interview questions — function-as-child, higher-order components, withAuth, cross-cutting concerns, hooks vs HOCs comparison.","react\u002Fpatterns\u002Frender-props-hoc","Render Props & HOCs","5b8a_FFY9oOxE5j6YoohtNraMG4vZoSdafVNh58xkH8",{"id":217,"title":218,"body":219,"description":32,"difficulty":34,"extension":35,"framework":10,"frameworkSlug":8,"meta":223,"navigation":37,"order":224,"path":225,"questions":226,"questionsCount":307,"related":119,"seo":308,"seoDescription":309,"stem":310,"subtopic":218,"topic":19,"topicSlug":21,"updated":123,"__hash__":311},"qa\u002Freact\u002Fpatterns\u002Ferror-boundaries.md","Error Boundaries",{"type":29,"value":220,"toc":221},[],{"title":32,"searchDepth":11,"depth":11,"links":222},[],{},3,"\u002Freact\u002Fpatterns\u002Ferror-boundaries",[227,231,235,239,243,247,251,255,259,263,267,271,275,279,283,287,291,295,299,303],{"id":228,"difficulty":42,"q":229,"a":230},"what-is-error-boundary","What is an error boundary and what problem does it solve in React?","An **error boundary** is a React class component that catches **JavaScript errors\nanywhere in its child component tree**, logs them, and renders a **fallback UI**\ninstead of crashing the whole application.\n\nBefore error boundaries existed, a single uncaught render error would unmount the\nentire React tree and leave users with a blank screen. Error boundaries provide\n**fault isolation** — only the subtree that threw is replaced with a fallback;\neverything outside the boundary keeps running normally.\n\n```jsx\n\u002F\u002F Without an error boundary, one bad render kills the whole app.\n\u002F\u002F With one, only the ErrorWidget section crashes — the rest survives.\n\u003CApp>\n  \u003CHeader \u002F>           {\u002F* still renders fine *\u002F}\n  \u003CErrorBoundary fallback={\u003Cp>Widget failed.\u003C\u002Fp>}>\n    \u003CErrorWidget \u002F>    {\u002F* throws → caught here, fallback shown *\u002F}\n  \u003C\u002FErrorBoundary>\n  \u003CFooter \u002F>           {\u002F* still renders fine *\u002F}\n\u003C\u002FApp>\n```\n\n**Rule of thumb:** An error boundary is a circuit breaker — it stops one bad\ncomponent from taking down the entire user interface.\n",{"id":232,"difficulty":34,"q":233,"a":234},"getDerivedStateFromError","What does getDerivedStateFromError do and when is it called?","`getDerivedStateFromError` is a **static lifecycle method** called during the\n**render phase** when a descendant throws. It receives the thrown error and must\nreturn an object that is merged into the component's state — typically a flag\nthat switches the component from rendering children to rendering the fallback UI.\n\nBecause it runs during the render phase it must be **pure and side-effect free**.\nUse it only to update state; do all logging in `componentDidCatch` instead.\n\n```jsx\nclass ErrorBoundary extends React.Component {\n  state = { hasError: false, error: null };\n\n  \u002F\u002F Called during render phase — update state to trigger fallback\n  static getDerivedStateFromError(error) {\n    return { hasError: true, error }; \u002F\u002F pure — no side effects here\n  }\n\n  render() {\n    if (this.state.hasError) {\n      return \u003Cp>Something went wrong.\u003C\u002Fp>; \u002F\u002F fallback UI\n    }\n    return this.props.children; \u002F\u002F normal path\n  }\n}\n```\n\n**Rule of thumb:** `getDerivedStateFromError` answers *what* to show; it must\nstay pure — keep it to one `return` statement that updates state.\n",{"id":236,"difficulty":34,"q":237,"a":238},"componentDidCatch","What is componentDidCatch and how does it differ from getDerivedStateFromError?","`componentDidCatch` is called during the **commit phase**, after the fallback UI\nhas been painted. Unlike `getDerivedStateFromError` it receives both the **error**\nand an **info object** (`{ componentStack }`) that contains the component stack\ntrace. It is the right place for **side effects** such as logging to an error\nmonitoring service.\n\nThe two methods are complementary: `getDerivedStateFromError` flips the state to\nshow the fallback; `componentDidCatch` does the logging.\n\n```jsx\nclass ErrorBoundary extends React.Component {\n  state = { hasError: false };\n\n  static getDerivedStateFromError() {\n    return { hasError: true }; \u002F\u002F render phase — only flip the flag\n  }\n\n  componentDidCatch(error, info) {\n    \u002F\u002F Commit phase — side effects are safe here\n    \u002F\u002F info.componentStack is the React component call stack\n    logErrorToSentry(error, { extra: { componentStack: info.componentStack } });\n  }\n\n  render() {\n    return this.state.hasError\n      ? \u003CFallbackUI \u002F>\n      : this.props.children;\n  }\n}\n```\n\n**Rule of thumb:** `getDerivedStateFromError` = pure state update (render phase);\n`componentDidCatch` = side effects like logging (commit phase). Use both together.\n",{"id":240,"difficulty":34,"q":241,"a":242},"why-class-component","Why must error boundaries be class components? Is there a hook-based alternative?","Error boundaries require `getDerivedStateFromError` and `componentDidCatch`, which\nare **class lifecycle methods** with no hook equivalents in React's public API. The\nReact team has acknowledged this gap but has not shipped a functional replacement —\nas of React 18 you still need a class component.\n\nThe `react-error-boundary` library wraps a class boundary behind a friendly\nfunctional API, which is the recommended way to avoid writing class components\nyourself in modern codebases.\n\n```jsx\n\u002F\u002F The class is unavoidable at the boundary itself…\nclass ErrorBoundary extends React.Component {\n  state = { hasError: false };\n  static getDerivedStateFromError() { return { hasError: true }; }\n  render() {\n    return this.state.hasError\n      ? this.props.fallback\n      : this.props.children;\n  }\n}\n\n\u002F\u002F …but you can wrap it so callers use a clean functional component:\nfunction SafeWidget({ children }) {\n  return (\n    \u003CErrorBoundary fallback={\u003Cp>Widget failed\u003C\u002Fp>}>\n      {children}\n    \u003C\u002FErrorBoundary>\n  );\n}\n```\n\n**Rule of thumb:** You need a class somewhere in the chain — use\n`react-error-boundary` to hide it so the rest of your codebase stays functional.\n",{"id":244,"difficulty":34,"q":245,"a":246},"errors-not-caught","What types of errors are NOT caught by error boundaries?","Error boundaries catch errors that occur during **rendering, lifecycle methods, and\nconstructors of class components** in the tree below them. They do NOT catch:\n\n- **Event handlers** — React does not call event handlers during rendering; wrap\n  them in a regular `try\u002Fcatch` instead.\n- **Asynchronous code** — errors in `setTimeout`, Promises, or `async\u002Fawait` are\n  not caught because they happen outside React's call stack.\n- **Server-side rendering** — boundaries only work client-side.\n- **Errors thrown inside the boundary itself** — a boundary cannot catch its own\n  render errors.\n\n```jsx\nfunction BadButton() {\n  const handleClick = () => {\n    try {\n      riskyOperation(); \u002F\u002F must use try\u002Fcatch — boundary won't catch this\n    } catch (err) {\n      reportError(err);\n    }\n  };\n  return \u003Cbutton onClick={handleClick}>Go\u003C\u002Fbutton>;\n}\n\nasync function fetchData() {\n  \u002F\u002F Promise rejection — NOT caught by error boundary\n  \u002F\u002F Use .catch() or try\u002Fcatch inside useEffect instead\n  const data = await api.get('\u002Fthings');\n}\n```\n\n**Rule of thumb:** If the error happens outside a React render call — in a\ncallback or a Promise — an error boundary will not catch it.\n",{"id":248,"difficulty":34,"q":249,"a":250},"error-boundary-granularity","At what granularity should you place error boundaries in an application?","**Coarser boundaries** protect large sections but may hide too much on failure.\n**Finer boundaries** give surgical fallbacks but add boilerplate. A typical\nthree-level strategy works well:\n\n1. **App\u002Froot level** — one top-level boundary as a last resort fallback (blank\n   screen prevention).\n2. **Route\u002Fpage level** — a boundary per route so a broken page doesn't kill\n   navigation.\n3. **Widget\u002Ffeature level** — boundaries around independent sidebar panels,\n   recommendation carousels, or ad slots that can fail without affecting the\n   main content.\n\n```jsx\n\u003CRootErrorBoundary>        {\u002F* level 1 — last resort *\u002F}\n  \u003CRouter>\n    \u003CRoutes>\n      \u003CRoute                 \u002F* level 2 — per route *\u002F\n        element={\n          \u003CRouteErrorBoundary>\n            \u003CDashboardPage \u002F>\n          \u003C\u002FRouteErrorBoundary>\n        }\n      \u002F>\n    \u003C\u002FRoutes>\n    \u003CSidebar>\n      \u003CWidgetErrorBoundary> {\u002F* level 3 — isolated widget *\u002F}\n        \u003CRecommendationsPanel \u002F>\n      \u003C\u002FWidgetErrorBoundary>\n    \u003C\u002FSidebar>\n  \u003C\u002FRouter>\n\u003C\u002FRootErrorBoundary>\n```\n\n**Rule of thumb:** Place a boundary wherever you can write a meaningful, scoped\nfallback message — the finer the boundary, the better the user experience.\n",{"id":252,"difficulty":42,"q":253,"a":254},"fallback-ui-design","What should a good fallback UI include?","A well-designed fallback UI tells users **what happened**, **what they can do\nnext**, and ideally provides a **recovery action** (reload, retry, go home).\nAvoid exposing raw error messages or stack traces in production.\n\nGood fallback UIs are:\n- **Scoped** — show only in the crashed section, not full-page unless necessary.\n- **Actionable** — include a retry button or a link to the home page.\n- **Branded** — styled consistently, not a plain white box.\n- **Non-alarming** — phrase errors in friendly, non-technical language.\n\n```jsx\nfunction FallbackUI({ error, resetErrorBoundary }) {\n  return (\n    \u003Cdiv role=\"alert\" className=\"error-panel\">\n      \u003Ch2>This section couldn't load.\u003C\u002Fh2>\n      {\u002F* Never show error.message to users in production *\u002F}\n      \u003Cp>Try refreshing or come back later.\u003C\u002Fp>\n      \u003Cbutton onClick={resetErrorBoundary}>Try again\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n**Rule of thumb:** A fallback UI should answer \"what broke and what can I do?\" —\nnever dump a raw error message onto users.\n",{"id":256,"difficulty":34,"q":257,"a":258},"error-recovery-reset","How do you implement error recovery — letting the user retry after a crash?","Recovery works by **resetting the boundary's error state** so it re-renders its\nchildren on the next render. In a hand-rolled boundary, expose a `reset` method\nor pass a `onReset` callback. In `react-error-boundary`, use the\n`resetErrorBoundary` prop injected into the fallback component.\n\nThe key subtlety: if the component that threw hasn't changed, it will throw again\nimmediately. Pair the reset with a **key change** or a data refetch so the\nre-render has a chance to succeed.\n\n```jsx\nclass ErrorBoundary extends React.Component {\n  state = { hasError: false };\n\n  static getDerivedStateFromError() { return { hasError: true }; }\n\n  \u002F\u002F Expose reset so parent or fallback can call it\n  reset = () => this.setState({ hasError: false });\n\n  render() {\n    if (this.state.hasError) {\n      return (\n        \u003CFallbackUI onRetry={this.reset} \u002F>  \u002F\u002F pass reset down\n      );\n    }\n    return this.props.children;\n  }\n}\n```\n\n**Rule of thumb:** Always give users a retry path — but also make sure the retry\nactually fixes the underlying condition, not just re-throws the same error.\n",{"id":260,"difficulty":34,"q":261,"a":262},"react-error-boundary-library","What does the react-error-boundary library provide over a hand-rolled boundary?","`react-error-boundary` is the community-standard wrapper that adds four key\nfeatures on top of the raw class API:\n\n1. **`\u003CErrorBoundary>`** — a ready-made class boundary that accepts `fallback`,\n   `FallbackComponent`, `onError`, `onReset`, and `resetKeys` props.\n2. **`FallbackComponent`** — receives `{ error, resetErrorBoundary }` so the\n   fallback can trigger recovery without prop drilling.\n3. **`resetKeys`** — an array of values; when any changes the boundary\n   auto-resets, enabling data-driven recovery.\n4. **`useErrorBoundary()`** — hook that lets any functional component throw\n   errors up to the nearest boundary programmatically (useful for async errors).\n\n```jsx\nimport { ErrorBoundary } from 'react-error-boundary';\n\nfunction Fallback({ error, resetErrorBoundary }) {\n  return (\n    \u003Cdiv role=\"alert\">\n      \u003Cp>Error: {error.message}\u003C\u002Fp>\n      \u003Cbutton onClick={resetErrorBoundary}>Retry\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  );\n}\n\n\u002F\u002F resetKeys: boundary auto-resets whenever `userId` changes\n\u003CErrorBoundary FallbackComponent={Fallback} resetKeys={[userId]}>\n  \u003CUserProfile userId={userId} \u002F>\n\u003C\u002FErrorBoundary>\n```\n\n**Rule of thumb:** Use `react-error-boundary` in production — it removes the need\nto write class components and handles the reset logic correctly.\n",{"id":264,"difficulty":34,"q":265,"a":266},"useErrorBoundary-hook","How does useErrorBoundary let functional components interact with an error boundary?","`useErrorBoundary` (from `react-error-boundary`) returns\n`{ showBoundary, resetBoundary }`. Calling `showBoundary(error)` throws the error\nup to the nearest `\u003CErrorBoundary>` as if it had been thrown during rendering.\nThis is the standard way to route **async and event-handler errors** through a\nboundary, since those errors are not caught automatically.\n\n```jsx\nimport { useErrorBoundary } from 'react-error-boundary';\n\nfunction UserList() {\n  const { showBoundary } = useErrorBoundary();\n\n  useEffect(() => {\n    fetchUsers()\n      .then(setUsers)\n      .catch((err) => {\n        showBoundary(err); \u002F\u002F manually escalate to nearest boundary\n      });\n  }, []);\n\n  return \u003Cul>{\u002F* ... *\u002F}\u003C\u002Ful>;\n}\n```\n\n**Rule of thumb:** Use `showBoundary` from `useErrorBoundary` any time you need\nto route a non-render error (async, event handler) into the boundary system.\n",{"id":268,"difficulty":34,"q":269,"a":270},"resetKeys-prop","What is the resetKeys prop in react-error-boundary and when should you use it?","`resetKeys` is an array of values passed to `\u003CErrorBoundary>`. Whenever any value\nin the array **changes between renders**, the boundary automatically resets its\nerror state and re-renders its children. This enables **data-driven recovery**\nwithout requiring the user to click a retry button.\n\nCommon use cases: resetting when the user navigates to a different resource\n(changing `userId`, `postId`), or when a query key changes after a refetch.\n\n```jsx\n\u002F\u002F Automatically retry when the user switches to a different profile\n\u003CErrorBoundary\n  FallbackComponent={ProfileError}\n  resetKeys={[userId]}       \u002F\u002F boundary resets whenever userId changes\n  onReset={() => refetch()}  \u002F\u002F also trigger a fresh network request\n>\n  \u003CUserProfile userId={userId} \u002F>\n\u003C\u002FErrorBoundary>\n```\n\n**Rule of thumb:** Use `resetKeys` when navigating between resources — it gives\nevery new resource a clean slate without manual reset button clicks.\n",{"id":272,"difficulty":34,"q":273,"a":274},"logging-to-sentry","How do you log errors to an external service like Sentry inside componentDidCatch?","`componentDidCatch` is the correct hook for external logging because it runs\nduring the **commit phase** where side effects are safe. It receives both the\n`error` and `info.componentStack`, which together give a useful trace for\ndebugging. Pass both to your monitoring SDK.\n\nWith `react-error-boundary`, use the `onError` prop instead of subclassing.\n\n```jsx\nimport * as Sentry from '@sentry\u002Freact';\n\n\u002F\u002F Option 1: hand-rolled class boundary\ncomponentDidCatch(error, info) {\n  Sentry.captureException(error, {\n    extra: { componentStack: info.componentStack },\n  });\n}\n\n\u002F\u002F Option 2: react-error-boundary — onError prop (preferred)\n\u003CErrorBoundary\n  FallbackComponent={Fallback}\n  onError={(error, info) => {\n    Sentry.captureException(error, {\n      extra: { componentStack: info.componentStack },\n    });\n  }}\n>\n  \u003CApp \u002F>\n\u003C\u002FErrorBoundary>\n```\n\n**Rule of thumb:** Always log both the error *and* the component stack —\n`error.message` tells you what crashed; `componentStack` tells you where.\n",{"id":276,"difficulty":95,"q":277,"a":278},"error-boundary-with-suspense","How do error boundaries work alongside React Suspense?","`\u003CSuspense>` handles **loading states** (a component \"suspends\" by throwing a\nPromise); error boundaries handle **error states** (a component throws an Error).\nThe two are designed to compose: wrap a `\u003CSuspense>` inside an `\u003CErrorBoundary>`\nto cover both loading and failure for the same subtree.\n\nIn concurrent mode, React can retry suspended trees. If a retry results in an\nError (not a Promise), the nearest error boundary catches it.\n\n```jsx\n\u002F\u002F Layered: error boundary wraps Suspense — covers both failure modes\n\u003CErrorBoundary FallbackComponent={ErrorFallback}>\n  \u003CSuspense fallback={\u003CSpinner \u002F>}>\n    {\u002F* LazyComponent suspends while loading → shows Spinner     *\u002F}\n    {\u002F* If it throws an Error instead → ErrorBoundary catches it *\u002F}\n    \u003CLazyComponent \u002F>\n  \u003C\u002FSuspense>\n\u003C\u002FErrorBoundary>\n```\n\n**Rule of thumb:** Wrap every `\u003CSuspense>` in an `\u003CErrorBoundary>` — Suspense\nonly handles the \"pending\" state; errors still need a boundary.\n",{"id":280,"difficulty":95,"q":281,"a":282},"boundary-in-concurrent-mode","Does concurrent mode (React 18) change how error boundaries behave?","Concurrent React introduces **partial rendering** and **retries**, which changes\nsome boundary behavior:\n\n- React may attempt to render a subtree **multiple times** before committing, so\n  `getDerivedStateFromError` might be called more than once for the same error.\n  The method must remain pure.\n- With `startTransition`, React can **defer** a failing render and keep the\n  previous UI visible rather than immediately showing the boundary fallback,\n  giving a smoother degradation.\n- In **Strict Mode (development only)** React double-invokes render to surface\n  impure code — `componentDidCatch` is *not* double-invoked, but\n  `getDerivedStateFromError` may be.\n\n```jsx\n\u002F\u002F Wrap a non-urgent update in a transition:\n\u002F\u002F if it errors, React keeps showing the stale UI instead of the fallback\nconst [isPending, startTransition] = useTransition();\n\nstartTransition(() => {\n  setResourceId(newId); \u002F\u002F error here → boundary catches, but only after transition\n});\n```\n\n**Rule of thumb:** Keep `getDerivedStateFromError` pure — concurrent mode may\ncall it multiple times before a single commit.\n",{"id":284,"difficulty":95,"q":285,"a":286},"error-boundary-itself-throws","What happens if an error boundary's own render method throws?","A boundary **cannot catch its own errors**. If `render()` or any lifecycle in the\nboundary class itself throws, React walks up the tree and looks for the next\nancestor error boundary. If none exists, the entire React tree is unmounted.\n\nThis means every error boundary implicitly relies on its parent being error-free —\nor being wrapped in another boundary. In practice, nest a minimal top-level\nboundary (that itself contains no complex logic) as the outermost root to catch\nanything a deeper boundary misses.\n\n```jsx\n\u002F\u002F A boundary that itself might fail — bad practice:\nclass RiskyBoundary extends React.Component {\n  static getDerivedStateFromError() { return { hasError: true }; }\n  render() {\n    if (this.state.hasError) {\n      return \u003CComplexFallbackThatMightAlsoThrow \u002F>; \u002F\u002F dangerous!\n    }\n    return this.props.children;\n  }\n}\n\n\u002F\u002F Keep fallback UI extremely simple — plain HTML, no data fetching:\nrender() {\n  if (this.state.hasError) {\n    return \u003Cp>Something went wrong.\u003C\u002Fp>; \u002F\u002F safe, cannot throw\n  }\n  return this.props.children;\n}\n```\n\n**Rule of thumb:** Keep fallback UI dead simple — it should be plain HTML or a\nstatic string, never something that fetches data or renders lazily.\n",{"id":288,"difficulty":34,"q":289,"a":290},"testing-error-boundaries","How do you test an error boundary with React Testing Library?","The standard approach is to render a component that **intentionally throws** and\nassert that the fallback UI appears. React Testing Library does not suppress the\nconsole error from React's internal boundary reporting, so you should spy on\n`console.error` and suppress it to keep test output clean.\n\n```jsx\nimport { render, screen } from '@testing-library\u002Freact';\nimport { ErrorBoundary } from 'react-error-boundary';\n\n\u002F\u002F A component that always throws\nfunction Bomb() {\n  throw new Error('💥 test error');\n}\n\ntest('renders fallback when child throws', () => {\n  \u002F\u002F Suppress React's console.error noise in test output\n  const spy = jest.spyOn(console, 'error').mockImplementation(() => {});\n\n  render(\n    \u003CErrorBoundary fallback={\u003Cp>Boundary caught it\u003C\u002Fp>}>\n      \u003CBomb \u002F>\n    \u003C\u002FErrorBoundary>\n  );\n\n  expect(screen.getByText('Boundary caught it')).toBeInTheDocument();\n  spy.mockRestore(); \u002F\u002F always restore after test\n});\n```\n\n**Rule of thumb:** Suppress `console.error` during boundary tests to keep output\nclean, but always restore the spy — suppressing it globally hides real issues.\n",{"id":292,"difficulty":34,"q":293,"a":294},"testing-reset-behavior","How do you test the reset\u002Fretry behavior of an error boundary?","Test recovery by simulating the retry action (clicking the button) and asserting\nthat the children render successfully after the error condition is cleared. Use\na **stateful wrapper** to toggle whether the child throws, simulating a data fix.\n\n```jsx\nlet shouldThrow = true;\n\nfunction MaybeThrow() {\n  if (shouldThrow) throw new Error('temporary failure');\n  return \u003Cp>Content loaded\u003C\u002Fp>;\n}\n\ntest('retries successfully after reset', async () => {\n  const spy = jest.spyOn(console, 'error').mockImplementation(() => {});\n\n  render(\n    \u003CErrorBoundary FallbackComponent={({ resetErrorBoundary }) => (\n      \u003Cbutton onClick={() => {\n        shouldThrow = false;     \u002F\u002F fix the condition before reset\n        resetErrorBoundary();    \u002F\u002F trigger boundary reset\n      }}>Retry\u003C\u002Fbutton>\n    )}>\n      \u003CMaybeThrow \u002F>\n    \u003C\u002FErrorBoundary>\n  );\n\n  await userEvent.click(screen.getByText('Retry'));\n  expect(screen.getByText('Content loaded')).toBeInTheDocument();\n  spy.mockRestore();\n});\n```\n\n**Rule of thumb:** Fix the error condition *before* calling `resetErrorBoundary`\n— otherwise the boundary resets and immediately throws again.\n",{"id":296,"difficulty":42,"q":297,"a":298},"error-boundary-vs-try-catch","When should you use an error boundary vs a try\u002Fcatch block in React code?","**Error boundaries** protect against uncaught errors in the **render cycle** —\nthey intercept errors in `render`, lifecycle methods, and constructors. They\nprovide a declarative, component-scoped safety net.\n\n**try\u002Fcatch** is for **imperative code** — event handlers, async operations,\nand utility functions outside the React render cycle where boundaries cannot reach.\n\n| Scenario | Tool |\n|---|---|\n| Component throws during render | Error boundary |\n| `async` fetch in `useEffect` | try\u002Fcatch + state |\n| Button click handler throws | try\u002Fcatch |\n| Lazy-loaded component fails | Error boundary + Suspense |\n\n```jsx\n\u002F\u002F Render error → boundary handles it automatically\nfunction BadRender() {\n  const data = JSON.parse(null); \u002F\u002F throws during render → boundary catches\n  return \u003Cdiv>{data.name}\u003C\u002Fdiv>;\n}\n\n\u002F\u002F Async error → try\u002Fcatch needed\nasync function loadUser(id) {\n  try {\n    return await api.getUser(id);\n  } catch (err) {\n    showBoundary(err); \u002F\u002F escalate manually via useErrorBoundary\n  }\n}\n```\n\n**Rule of thumb:** Use boundaries for render errors, try\u002Fcatch for everything\nelse — then bridge async failures into boundaries via `showBoundary`.\n",{"id":300,"difficulty":42,"q":301,"a":302},"multiple-boundaries-strategy","Can you have multiple error boundaries in the same component tree? How should they be nested?","Yes — React will propagate an unhandled error **up the tree** until it finds the\nnearest ancestor error boundary. Multiple nested boundaries each act as\nindependent catch points for their own subtrees.\n\nA healthy app has **multiple boundaries at different levels**:\n\n- The root boundary is the final backstop.\n- Route-level boundaries isolate page failures.\n- Widget-level boundaries isolate autonomous sections.\n\n```jsx\n\u002F\u002F Each boundary is independent — inner boundary failing falls up to outer\n\u003CAppBoundary>          {\u002F* outer: catches everything the inner misses *\u002F}\n  \u003CLayout>\n    \u003CNavBoundary>      {\u002F* isolates nav errors *\u002F}\n      \u003CNavigation \u002F>\n    \u003C\u002FNavBoundary>\n\n    \u003CPageBoundary>     {\u002F* isolates current page errors *\u002F}\n      \u003CMainContent>\n        \u003CWidgetBoundary> {\u002F* isolates a single widget *\u002F}\n          \u003CLiveFeed \u002F>\n        \u003C\u002FWidgetBoundary>\n      \u003C\u002FMainContent>\n    \u003C\u002FPageBoundary>\n  \u003C\u002FLayout>\n\u003C\u002FAppBoundary>\n```\n\n**Rule of thumb:** Think of boundaries like `try\u002Fcatch` nesting — the innermost\nmatching boundary catches the error; outer ones only fire if the inner one itself\nfails or doesn't exist.\n",{"id":304,"difficulty":42,"q":305,"a":306},"production-vs-development","Why do error boundaries behave differently in development vs production?","In **development** (`react-dom\u002Fdevelopment`), React re-throws errors after calling\nthe boundary so that the browser's DevTools overlay and the console both show the\nfull stack trace. This means you'll see the error in the console **even when a\nboundary catches it** — that's intentional, not a bug.\n\nIn **production** (`react-dom\u002Fproduction`), the error is caught silently by the\nboundary, the fallback UI is shown, and no overlay appears. Users see only the\nfallback; developers see nothing unless logging (Sentry, etc.) is set up.\n\n```jsx\n\u002F\u002F Dev: React error overlay appears + console.error fires even with a boundary.\n\u002F\u002F This tells developers the error happened; the boundary still works in prod.\n\n\u002F\u002F A common mistake: developers test boundaries in dev, see the overlay,\n\u002F\u002F and think the boundary isn't working — it is; the overlay is just dev behavior.\n\ncomponentDidCatch(error, info) {\n  \u002F\u002F This is your ONLY visibility into boundary-caught errors in production\n  logToMonitoringService(error, info);\n}\n```\n\n**Rule of thumb:** The dev error overlay does not mean the boundary failed —\nReact shows it deliberately; always test production behavior with `npm run build`.\n",20,{"description":32},"React error boundary interview questions — componentDidCatch, getDerivedStateFromError, fallback UI, error recovery, async errors, and react-error-boundary library.","react\u002Fpatterns\u002Ferror-boundaries","HclcDy5UUQv4iAGr42ulavhLi8--jWKoMfQiQ1_LMnU",{"id":313,"title":314,"body":315,"description":32,"difficulty":34,"extension":35,"framework":10,"frameworkSlug":8,"meta":319,"navigation":37,"order":320,"path":321,"questions":322,"questionsCount":307,"related":119,"seo":403,"seoDescription":404,"stem":405,"subtopic":406,"topic":19,"topicSlug":21,"updated":123,"__hash__":407},"qa\u002Freact\u002Fpatterns\u002Fportals-refs.md","Portals Refs",{"type":29,"value":316,"toc":317},[],{"title":32,"searchDepth":11,"depth":11,"links":318},[],{},4,"\u002Freact\u002Fpatterns\u002Fportals-refs",[323,327,331,335,339,343,347,351,355,359,363,367,371,375,379,383,387,391,395,399],{"id":324,"difficulty":42,"q":325,"a":326},"what-is-createportal","What does ReactDOM.createPortal do and when should you use it?","`ReactDOM.createPortal(children, domNode)` renders `children` into a **different\nDOM node** than the component's parent, while keeping them inside the **React\ncomponent tree**. The portal children still receive context, state, and events\nfrom their React parent — only the DOM placement changes.\n\n```jsx\nimport { createPortal } from 'react-dom'\n\nfunction Modal({ children, onClose }) {\n  return createPortal(\n    \u002F\u002F JSX rendered here...\n    \u003Cdiv className=\"modal-overlay\" onClick={onClose}>\n      \u003Cdiv className=\"modal-content\" onClick={e => e.stopPropagation()}>\n        {children}\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>,\n    \u002F\u002F ...but mounted into this DOM node, outside the app root\n    document.getElementById('modal-root')\n  )\n}\n```\n\nUse portals when you need a component to **escape the CSS stacking context** of\nits parent — modals, tooltips, dropdown menus, toasts, and popovers all commonly\nneed to render at the `\u003Cbody>` level to avoid `overflow: hidden` or `z-index`\nclipping from ancestor elements.\n\n**Rule of thumb:** Reach for `createPortal` any time a UI element needs to visually\nfloat above the rest of the page, regardless of where it lives in the component tree.\n",{"id":328,"difficulty":34,"q":329,"a":330},"portal-react-tree-vs-dom-tree","A portal renders its children in a different DOM node. Does that affect React context or event propagation?","No — portals are a **DOM-only escape hatch**. React's virtual component tree is\nunchanged, so everything that flows through the React tree — **context values,\nstate, refs, and synthetic events** — still works as if the portal were rendered\ninline.\n\n```jsx\nfunction App() {\n  const [theme] = useContext(ThemeContext) \u002F\u002F 'dark'\n\n  return (\n    \u003CThemeContext.Provider value=\"dark\">\n      \u003CModal>\n        {\u002F* ThemeContext reads 'dark' even though Modal\n            is mounted under document.body in the DOM *\u002F}\n        \u003CThemedButton \u002F>\n      \u003C\u002FModal>\n    \u003C\u002FThemeContext.Provider>\n  )\n}\n```\n\nThis means a portal component can consume any context provided by its React\nancestors, even if those ancestors are DOM siblings or even DOM ancestors of the\nportal's mount point.\n\n**Rule of thumb:** Think of portals as a teleport for DOM placement only — the\nReact component lineage is unaffected, so all React features keep working normally.\n",{"id":332,"difficulty":34,"q":333,"a":334},"portal-event-bubbling-gotcha","How do synthetic events bubble through a portal? Why is this a common interview gotcha?","Synthetic events inside a portal bubble **through the React component tree, not\nthe DOM tree**. A click inside a modal portal bubbles up to the React ancestor\nthat rendered the portal, even though the modal's DOM node is a sibling of\n`#root` in the actual DOM.\n\n```jsx\nfunction Page() {\n  \u002F\u002F This handler fires when the button inside Modal is clicked,\n  \u002F\u002F because the portal's React parent is Page — even though\n  \u002F\u002F the modal DOM is outside #root entirely.\n  const handleClick = () => console.log('caught in Page')\n\n  return (\n    \u003Cdiv onClick={handleClick}>\n      \u003CModal>\n        \u003Cbutton>Click me\u003C\u002Fbutton> {\u002F* bubbles to Page via React tree *\u002F}\n      \u003C\u002FModal>\n    \u003C\u002Fdiv>\n  )\n}\n```\n\nThe gotcha: if you add a `document.addEventListener('click', ...)` outside React\nand expect portal clicks to bubble through the DOM, you'll see them — but a React\n`onClick` placed on a DOM ancestor of `#root` will also fire because the native\nevent does travel through the real DOM too. The **React synthetic event** system\nis what bubbles through the React tree.\n\n**Rule of thumb:** Always think of event bubbling in terms of the React component\ntree, not the rendered DOM tree — portals don't change the React ancestry.\n",{"id":336,"difficulty":42,"q":337,"a":338},"portal-modal-z-index-escape","Why do modals rendered inside a deeply nested component often break z-index stacking, and how does createPortal fix it?","CSS `z-index` is scoped to a **stacking context**. An ancestor with\n`transform`, `opacity \u003C 1`, `position: relative\u002Fabsolute` and a `z-index`, or\n`overflow: hidden` creates a new stacking context that caps the `z-index` of all\nits descendants. A modal with `z-index: 9999` is still trapped below an ancestor\nwith `z-index: 1` if that ancestor forms its own stacking context.\n\n```jsx\n\u002F\u002F Without portal — modal trapped inside stacking context of .card\n\u002F\u002F \u003Cdiv class=\"card\" style=\"transform: translateZ(0); z-index: 1\">\n\u002F\u002F   \u003CModal \u002F>   ← z-index: 9999 but still below sibling stacking contexts\n\u002F\u002F \u003C\u002Fdiv>\n\n\u002F\u002F With portal — modal escapes to body, outside all stacking contexts\nfunction Modal({ children }) {\n  return createPortal(\n    \u003Cdiv className=\"modal\" style={{ zIndex: 9999 }}>\n      {children}\n    \u003C\u002Fdiv>,\n    document.body \u002F\u002F top-level stacking context\n  )\n}\n```\n\nPortaling to `document.body` (or a dedicated `#modal-root` sibling of `#root`)\nremoves the modal from all ancestor stacking contexts and lets it freely float\nabove every other element.\n\n**Rule of thumb:** If a modal or tooltip is clipped or covered despite a high\n`z-index`, the component tree has a stacking context trap — use `createPortal`\nto escape it.\n",{"id":340,"difficulty":34,"q":341,"a":342},"portal-accessibility-focus","How should you handle focus management and accessibility for a portal-based modal?","A modal portal must manage **focus trap**, **aria attributes**, and **keyboard\ndismissal** explicitly, because rendering outside the normal DOM flow doesn't\nautomatically handle any of these.\n\n```jsx\nimport { useEffect, useRef } from 'react'\nimport { createPortal } from 'react-dom'\n\nfunction Modal({ isOpen, onClose, children }) {\n  const dialogRef = useRef(null)\n\n  useEffect(() => {\n    if (!isOpen) return\n    \u002F\u002F Move focus into the modal when it opens\n    dialogRef.current?.focus()\n    \u002F\u002F Close on Escape\n    const onKey = (e) => e.key === 'Escape' && onClose()\n    document.addEventListener('keydown', onKey)\n    return () => document.removeEventListener('keydown', onKey)\n  }, [isOpen, onClose])\n\n  if (!isOpen) return null\n\n  return createPortal(\n    \u003Cdiv\n      role=\"dialog\"\n      aria-modal=\"true\"\n      tabIndex={-1}  \u002F\u002F makes div focusable\n      ref={dialogRef}\n      className=\"modal\"\n    >\n      {children}\n    \u003C\u002Fdiv>,\n    document.body\n  )\n}\n```\n\nKey requirements: `role=\"dialog\"`, `aria-modal=\"true\"` (tells screen readers\nto ignore background content), focus moved into the dialog on open, and Escape\nkey closes it. Libraries like `focus-trap-react` automate the focus-trap cycle.\n\n**Rule of thumb:** A portal gives you DOM freedom, but accessibility is still\nyour responsibility — always add `role=\"dialog\"`, `aria-modal`, and focus management.\n",{"id":344,"difficulty":34,"q":345,"a":346},"portal-cleanup","How does React clean up a portal when the component unmounts?","React automatically removes portal content from the DOM when the component\nthat rendered the portal unmounts. You do not need to manually call\n`ReactDOM.unmountComponentAtNode` for standard portals.\n\n```jsx\nfunction App() {\n  const [showModal, setShowModal] = useState(false)\n\n  return (\n    \u003C>\n      \u003Cbutton onClick={() => setShowModal(true)}>Open\u003C\u002Fbutton>\n      {\u002F* When showModal becomes false, React unmounts Modal and\n          removes its portal DOM from document.body automatically *\u002F}\n      {showModal && (\n        \u003CModal onClose={() => setShowModal(false)}>\n          \u003Cp>Content\u003C\u002Fp>\n        \u003C\u002FModal>\n      )}\n    \u003C\u002F>\n  )\n}\n```\n\nIf you **dynamically created the mount node** yourself (e.g. with\n`document.createElement('div')` and `appendChild`), you are responsible for\nremoving that container element in a cleanup function or `useEffect` return.\nThe portal content inside it is still cleaned by React; the container node\nitself is your concern.\n\n**Rule of thumb:** Let React manage unmounting; only clean up manually if you\ncreated the portal's host DOM element dynamically outside of React.\n",{"id":348,"difficulty":95,"q":349,"a":350},"portal-testing","How do you test a component that uses createPortal?","Jest + React Testing Library (RTL) works with portals out of the box because\nRTL renders into `document.body` by default and `createPortal` also targets\n`document.body` — so portal content is in `document.body` and queryable normally.\n\n```jsx\n\u002F\u002F Modal.test.jsx\nimport { render, screen } from '@testing-library\u002Freact'\nimport userEvent from '@testing-library\u002Fuser-event'\nimport Modal from '.\u002FModal'\n\ntest('renders portal content in document.body', () => {\n  render(\u003CModal isOpen onClose={() => {}}>Hello portal\u003C\u002FModal>)\n  \u002F\u002F Even though content is in a portal, RTL queries search document.body\n  expect(screen.getByText('Hello portal')).toBeInTheDocument()\n})\n\ntest('calls onClose on Escape key', async () => {\n  const onClose = jest.fn()\n  render(\u003CModal isOpen onClose={onClose}>Content\u003C\u002FModal>)\n  await userEvent.keyboard('{Escape}')\n  expect(onClose).toHaveBeenCalled()\n})\n```\n\nIf your portal targets a custom node (e.g. `document.getElementById('modal-root')`),\nadd `\u003Cdiv id=\"modal-root\" \u002F>` to `document.body` in a `beforeEach` and clean it\nup in `afterEach`.\n\n**Rule of thumb:** RTL's document-level query approach means portals require no\nspecial setup — only custom mount targets need a manual DOM fixture.\n",{"id":352,"difficulty":42,"q":353,"a":354},"what-is-useref","What does useRef return and what are its two main use cases?","`useRef(initialValue)` returns a **plain mutable object** `{ current: initialValue }`\nthat persists for the entire lifetime of the component. Mutating `.current` does\n**not** trigger a re-render.\n\n```jsx\n\u002F\u002F Use case 1: DOM access\nfunction TextInput() {\n  const inputRef = useRef(null)\n  const focus = () => inputRef.current.focus() \u002F\u002F imperative DOM call\n  return \u003Cinput ref={inputRef} \u002F>\n}\n\n\u002F\u002F Use case 2: mutable container (timer id, previous value, etc.)\nfunction Interval() {\n  const timerId = useRef(null)\n  const start = () => { timerId.current = setInterval(tick, 1000) }\n  const stop = () => clearInterval(timerId.current)\n  return \u003C>\u003Cbutton onClick={start}>Start\u003C\u002Fbutton>\u003Cbutton onClick={stop}>Stop\u003C\u002Fbutton>\u003C\u002F>\n}\n```\n\nThe two distinct jobs: (1) **hold a reference to a DOM element** so you can call\nimperative DOM APIs (focus, scroll, measure); (2) **store any mutable value** that\nmust survive re-renders without causing them — timers, intervals, previous state,\nanimation frame IDs, WebSocket instances.\n\n**Rule of thumb:** If you need to read or write a value across renders without\ntriggering one, `useRef` is the right tool — it's essentially instance state for\nfunction components.\n",{"id":356,"difficulty":34,"q":357,"a":358},"ref-vs-state","What is the key difference between a ref and state, and when would you choose one over the other?","The fundamental difference: **state changes schedule a re-render; ref mutations\ndo not**. Both persist across renders, but only state drives the UI.\n\n```jsx\nfunction Counter() {\n  const [count, setCount] = useState(0) \u002F\u002F changing → re-render\n  const renderCount = useRef(0)         \u002F\u002F changing → no re-render\n\n  useEffect(() => {\n    renderCount.current += 1 \u002F\u002F track silently, no render loop\n  })\n\n  return (\n    \u003Cdiv>\n      \u003Cp>Count: {count}\u003C\u002Fp>                       {\u002F* must be state *\u002F}\n      \u003Cp>Renders: {renderCount.current}\u003C\u002Fp>       {\u002F* stale between renders, but OK here *\u002F}\n      \u003Cbutton onClick={() => setCount(c => c + 1)}>+1\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  )\n}\n```\n\nRef mutations are also **synchronous** — `ref.current` updates immediately with\nno batching. State updates may be batched and applied asynchronously.\n\nChoose **state** when the value needs to appear in the rendered output or drive\nconditional logic inside JSX. Choose **ref** when the value is used by event\nhandlers \u002F effects only and shouldn't re-render the component when it changes.\n\n**Rule of thumb:** If a value needs to be visible in the UI, it must be state;\nif it's behind-the-scenes bookkeeping, a ref keeps the render cycle clean.\n",{"id":360,"difficulty":34,"q":361,"a":362},"callback-ref","What is a callback ref and when is it more useful than useRef?","A **callback ref** is a function passed to the `ref` prop instead of a ref\nobject. React calls it with the DOM node when the component mounts, and with\n`null` when it unmounts.\n\n```jsx\nfunction MeasuredBox() {\n  const [height, setHeight] = useState(0)\n\n  \u002F\u002F Called once with the DOM node on mount, null on unmount\n  const measuredRef = useCallback((node) => {\n    if (node !== null) {\n      setHeight(node.getBoundingClientRect().height)\n    }\n  }, []) \u002F\u002F stable reference — no re-registration on every render\n\n  return (\n    \u003Cdiv ref={measuredRef}>\n      Height is {height}px\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n`useRef` gives you the node after render but doesn't notify you when the node\nchanges. A callback ref is superior when you need to **react to the node being\nattached or detached** — measuring layout after conditional rendering, attaching\nthird-party libraries imperatively, or observing dynamic child nodes.\n\n**Rule of thumb:** Use `useRef` for stable, always-mounted nodes; use a callback\nref when you need to run code the moment the element appears or disappears in the DOM.\n",{"id":364,"difficulty":34,"q":365,"a":366},"ref-forwarding","What is ref forwarding and why is it needed for custom components?","By default, the `ref` prop on a custom component is **not forwarded** to the\nunderlying DOM element — React reserves `ref` and doesn't pass it through `props`.\n`React.forwardRef` opts a component into forwarding the ref to a child element.\n\n```jsx\n\u002F\u002F Without forwardRef: ref on \u003CFancyInput> points to nothing useful\n\u002F\u002F With forwardRef: ref reaches the real \u003Cinput>\nconst FancyInput = React.forwardRef((props, ref) => (\n  \u003Cinput\n    {...props}\n    ref={ref}              \u002F\u002F forwarded ref attached to DOM input\n    className=\"fancy\"\n  \u002F>\n))\n\n\u002F\u002F Parent can now focus the input imperatively\nfunction Form() {\n  const inputRef = useRef(null)\n  return (\n    \u003C>\n      \u003CFancyInput ref={inputRef} placeholder=\"Type here\" \u002F>\n      \u003Cbutton onClick={() => inputRef.current.focus()}>Focus\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\nRef forwarding is common in **design-system \u002F component-library** components\n(buttons, inputs, modals) that wrap a native element but need to expose the DOM\nnode to consumers for accessibility or focus management.\n\n**Rule of thumb:** Any reusable component that wraps a DOM element should use\n`forwardRef` so library consumers retain imperative DOM access.\n",{"id":368,"difficulty":95,"q":369,"a":370},"useimperativehandle","What does useImperativeHandle do, and when should you use it?","`useImperativeHandle(ref, createHandle, deps)` lets a child component **control\nwhat the parent's ref exposes** — instead of exposing the raw DOM node, it\nexposes a custom object with only the methods the parent should call.\n\n```jsx\nconst VideoPlayer = React.forwardRef((props, ref) => {\n  const videoRef = useRef(null)\n\n  \u002F\u002F Parent only gets play\u002Fpause — not direct DOM access\n  useImperativeHandle(ref, () => ({\n    play: () => videoRef.current.play(),\n    pause: () => videoRef.current.pause(),\n  }), [])\n\n  return \u003Cvideo ref={videoRef} src={props.src} \u002F>\n})\n\nfunction App() {\n  const playerRef = useRef(null)\n  return (\n    \u003C>\n      \u003CVideoPlayer ref={playerRef} src=\"\u002Fclip.mp4\" \u002F>\n      \u003Cbutton onClick={() => playerRef.current.play()}>Play\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\nThis is an **encapsulation tool**: it prevents parent components from reaching\ninto child internals and calling arbitrary DOM methods, keeping the API surface\nintentionally minimal.\n\n**Rule of thumb:** Prefer `useImperativeHandle` over raw `forwardRef` whenever\nyou need to expose imperative behavior from a child component — it enforces a\nclean, intentional API boundary.\n",{"id":372,"difficulty":34,"q":373,"a":374},"ref-mutable-container-previous-value","How do you use a ref to track the previous value of a prop or state variable?","Refs persist across renders without resetting, so they're perfect for storing\nthe **value from the last render** before state\u002Fprops update. The pattern is a\none-liner `useEffect` that writes `.current` after every render.\n\n```jsx\nfunction usePrevious(value) {\n  const ref = useRef(undefined)\n\n  useEffect(() => {\n    \u002F\u002F Runs after render — so during the current render, ref.current\n    \u002F\u002F still holds the value from the PREVIOUS render\n    ref.current = value\n  })\n\n  return ref.current \u002F\u002F previous render's value\n}\n\nfunction PriceDisplay({ price }) {\n  const prevPrice = usePrevious(price)\n  const direction = price > prevPrice ? '▲' : '▼'\n  return \u003Cspan>{price} {prevPrice !== undefined && direction}\u003C\u002Fspan>\n}\n```\n\nThis works because `useEffect` runs after the render is committed to the DOM.\nDuring the render that reads `ref.current`, the effect from the previous render\nhas already written the old value in, but the new value hasn't been written yet.\n\n**Rule of thumb:** Store previous values in a ref, not state — reading the\nprevious value shouldn't cause an extra re-render.\n",{"id":376,"difficulty":34,"q":377,"a":378},"ref-timeout-cleanup","Why should you store setTimeout or setInterval IDs in a ref rather than state?","Storing a timer ID in **state** would trigger a re-render every time you start\nor clear a timer, which is wasteful and can cause cascading effects. A **ref**\nstores it silently.\n\n```jsx\nfunction Debounced({ onSearch }) {\n  const timerRef = useRef(null)\n\n  const handleChange = (e) => {\n    \u002F\u002F Cancel previous timer without re-rendering\n    clearTimeout(timerRef.current)\n    timerRef.current = setTimeout(() => {\n      onSearch(e.target.value)\n    }, 300)\n  }\n\n  \u002F\u002F Clean up on unmount to prevent calling onSearch after component is gone\n  useEffect(() => {\n    return () => clearTimeout(timerRef.current)\n  }, [])\n\n  return \u003Cinput onChange={handleChange} \u002F>\n}\n```\n\nThe same pattern applies to `requestAnimationFrame` IDs, `setInterval` IDs,\nWebSocket instances, and Intersection\u002FResizeObserver instances — anything that\nneeds to be cancelled\u002Fdestroyed on unmount but doesn't affect the render output.\n\n**Rule of thumb:** Anything you'd cancel in cleanup belongs in a ref, not state —\ntimer IDs and resource handles are bookkeeping, not UI data.\n",{"id":380,"difficulty":34,"q":381,"a":382},"accessing-child-dom-from-parent","How do you access a child component's DOM node from a parent component?","The standard approach is `React.forwardRef` in the child, which allows the\nparent to pass a ref that the child attaches to its DOM element.\n\n```jsx\n\u002F\u002F Child forwards ref to its inner \u003Cdiv>\nconst Card = React.forwardRef(({ title, children }, ref) => (\n  \u003Cdiv ref={ref} className=\"card\">\n    \u003Ch2>{title}\u003C\u002Fh2>\n    {children}\n  \u003C\u002Fdiv>\n))\n\n\u002F\u002F Parent attaches ref and can read the DOM node\nfunction Page() {\n  const cardRef = useRef(null)\n\n  const scrollIntoView = () => {\n    cardRef.current?.scrollIntoView({ behavior: 'smooth' })\n  }\n\n  return (\n    \u003C>\n      \u003Cbutton onClick={scrollIntoView}>Scroll to card\u003C\u002Fbutton>\n      \u003CCard ref={cardRef} title=\"Target\">content\u003C\u002FCard>\n    \u003C\u002F>\n  )\n}\n```\n\nFor class components, a plain `ref` already points to the class instance, so\nyou can call public methods directly without `forwardRef`. For function\ncomponents, `forwardRef` + optionally `useImperativeHandle` is the only way.\n\n**Rule of thumb:** Always use `forwardRef` in any reusable function component\nthat wraps a DOM element — parents often need scroll, focus, or measurement access.\n",{"id":384,"difficulty":95,"q":385,"a":386},"refs-as-design-smell","When do refs indicate a design smell in a React component?","Refs are an **imperative escape hatch** — reaching for them frequently is a sign\nthe component is fighting React's declarative model instead of working with it.\n\n```jsx\n\u002F\u002F Smell: using ref to read input value instead of controlled state\nfunction BadForm() {\n  const inputRef = useRef(null)\n  const submit = () => console.log(inputRef.current.value) \u002F\u002F side-channel read\n  return \u003C>\u003Cinput ref={inputRef} \u002F>\u003Cbutton onClick={submit}>Send\u003C\u002Fbutton>\u003C\u002F>\n}\n\n\u002F\u002F Better: controlled component — value lives in React state\nfunction GoodForm() {\n  const [value, setValue] = useState('')\n  const submit = () => console.log(value) \u002F\u002F just reads state\n  return (\n    \u003C>\n      \u003Cinput value={value} onChange={e => setValue(e.target.value)} \u002F>\n      \u003Cbutton onClick={submit}>Send\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\nOther ref-as-smell patterns: using a ref to trigger a re-render manually (use\nstate), using a ref to share data between sibling components (lift state or use\ncontext), and using refs to replicate what `useEffect` dependencies should handle.\n\n**Rule of thumb:** If you're reaching for a ref to solve a problem involving\nrendering or data flow, step back — there's almost certainly a declarative solution\nusing state, context, or derived values.\n",{"id":388,"difficulty":95,"q":389,"a":390},"ref-render-cycle","Why can't you reliably read a ref's value during the render phase?","Refs are **mutable and not part of React's render model**. React may render a\ncomponent multiple times before committing (strict mode renders twice in dev;\nconcurrent mode may discard renders). Refs are only reliably up to date **after\ncommit** (i.e. inside effects and event handlers).\n\n```jsx\nfunction Broken() {\n  const ref = useRef(0)\n  ref.current++ \u002F\u002F mutated during render — unreliable in concurrent mode\n\n  \u002F\u002F If React renders this component but discards the output,\n  \u002F\u002F ref.current has been incremented but nothing was committed.\n  return \u003Cp>Renders: {ref.current}\u003C\u002Fp> \u002F\u002F stale \u002F unpredictable\n}\n\n\u002F\u002F Correct: mutate refs only in effects or event handlers\nfunction Fixed() {\n  const ref = useRef(0)\n  useEffect(() => { ref.current++ }) \u002F\u002F runs only after commit\n  return \u003Cp>...\u003C\u002Fp>\n}\n```\n\nReading a ref in JSX (displaying `ref.current`) is also fragile because React\nwon't schedule a re-render when `.current` changes, so the displayed value goes\nstale silently.\n\n**Rule of thumb:** Treat refs as post-commit bookkeeping — read and write `.current`\nonly inside effects and event handlers, never directly in the render function body.\n",{"id":392,"difficulty":42,"q":393,"a":394},"portal-vs-conditional-render","When should you use a portal versus simply conditionally rendering a component at the top of the tree?","Both approaches can place a modal high in the DOM, but they have different\ntradeoffs for **component co-location** and **CSS context**.\n\n```jsx\n\u002F\u002F Option A: lift modal to App — modal logic scattered from its trigger\nfunction App() {\n  const [open, setOpen] = useState(false)\n  return (\n    \u003C>\n      {open && \u003CModal onClose={() => setOpen(false)} \u002F>} {\u002F* far from trigger *\u002F}\n      \u003CDeepTree onTrigger={() => setOpen(true)} \u002F>\n    \u003C\u002F>\n  )\n}\n\n\u002F\u002F Option B: portal — modal stays co-located with its trigger, escapes DOM\nfunction TriggerButton() {\n  const [open, setOpen] = useState(false)\n  return (\n    \u003C>\n      \u003Cbutton onClick={() => setOpen(true)}>Open Modal\u003C\u002Fbutton>\n      {open && \u003CModal onClose={() => setOpen(false)} \u002F>} {\u002F* portal inside *\u002F}\n    \u003C\u002F>\n  )\n}\n```\n\nPortals let you keep state and logic **co-located** with the component that owns\nthem while still rendering the output at the top of the DOM. Lifting state\nachieves DOM placement but couples the modal logic to a distant ancestor.\n\n**Rule of thumb:** Use a portal when co-location matters and a CSS escape is\nneeded; lift state to the root only when multiple unrelated components need to\ncontrol the same modal.\n",{"id":396,"difficulty":34,"q":397,"a":398},"ref-scroll-measure","How do you use a ref to scroll to an element or measure its dimensions?","Attaching a ref to a DOM element gives you the raw `HTMLElement`, so you can\ncall any imperative DOM API — `scrollIntoView`, `getBoundingClientRect`,\n`offsetHeight`, etc. Measurements must happen **after the element has rendered**,\nwhich means inside a `useEffect` or an event handler.\n\n```jsx\nfunction ChatWindow({ messages }) {\n  const bottomRef = useRef(null)\n  const containerRef = useRef(null)\n  const [containerHeight, setContainerHeight] = useState(0)\n\n  \u002F\u002F Scroll to bottom whenever messages change\n  useEffect(() => {\n    bottomRef.current?.scrollIntoView({ behavior: 'smooth' })\n  }, [messages])\n\n  \u002F\u002F Measure container after first render\n  useEffect(() => {\n    if (containerRef.current) {\n      setContainerHeight(containerRef.current.getBoundingClientRect().height)\n    }\n  }, [])\n\n  return (\n    \u003Cdiv ref={containerRef} className=\"chat-window\">\n      {messages.map(m => \u003CMessage key={m.id} data={m} \u002F>)}\n      \u003Cdiv ref={bottomRef} \u002F> {\u002F* sentinel element at the bottom *\u002F}\n    \u003C\u002Fdiv>\n  )\n}\n```\n\nFor **layout measurements that need to happen before the browser paints**, use\n`useLayoutEffect` instead of `useEffect` — it fires synchronously after DOM\nmutations but before the browser renders, avoiding a visible flash.\n\n**Rule of thumb:** Use `useEffect` for scroll commands (visual, after paint is\nfine) and `useLayoutEffect` for measurements that affect what gets rendered,\nsince those must happen before the user sees the result.\n",{"id":400,"difficulty":34,"q":401,"a":402},"multiple-portals","Can you render multiple portals on the same page, and how should you manage their mount points?","Yes — you can have as many portals as you like. Each `createPortal` call is\nindependent and can target the **same or different** DOM nodes.\n\n```jsx\n\u002F\u002F index.html — dedicated mount points alongside #root\n\u002F\u002F \u003Cdiv id=\"root\">\u003C\u002Fdiv>\n\u002F\u002F \u003Cdiv id=\"modal-root\">\u003C\u002Fdiv>\n\u002F\u002F \u003Cdiv id=\"tooltip-root\">\u003C\u002Fdiv>\n\nfunction Tooltip({ content, anchor }) {\n  return createPortal(\n    \u003Cdiv className=\"tooltip\">{content}\u003C\u002Fdiv>,\n    document.getElementById('tooltip-root') \u002F\u002F dedicated node\n  )\n}\n\nfunction Modal({ children }) {\n  return createPortal(\n    \u003Cdiv className=\"modal-overlay\">{children}\u003C\u002Fdiv>,\n    document.getElementById('modal-root') \u002F\u002F separate node for stacking control\n  )\n}\n```\n\nSeparating mount nodes gives you **CSS stacking control** between portal types —\n`#modal-root` can have a higher `z-index` base than `#tooltip-root` at the body\nlevel, without needing per-element `z-index` wars.\n\n**Rule of thumb:** Provision a dedicated `\u003Cdiv>` for each class of portal\n(modals, tooltips, toasts) in `index.html` so their stacking order is\ndetermined structurally, not by arbitrary `z-index` values.\n",{"description":32},"React portals and refs interview questions — createPortal, DOM escape hatches, useRef, callback refs, ref forwarding, and direct DOM manipulation patterns.","react\u002Fpatterns\u002Fportals-refs","Portals & Refs","NfTRyqGUI9gF4wkwTyXVqCdmHs08NsxKVml1iJSZVjc",{"id":409,"title":410,"body":411,"description":32,"difficulty":95,"extension":35,"framework":10,"frameworkSlug":8,"meta":415,"navigation":37,"order":416,"path":417,"questions":418,"questionsCount":307,"related":119,"seo":499,"seoDescription":500,"stem":501,"subtopic":502,"topic":19,"topicSlug":21,"updated":123,"__hash__":503},"qa\u002Freact\u002Fpatterns\u002Fforward-ref-imperative.md","Forward Ref Imperative",{"type":29,"value":412,"toc":413},[],{"title":32,"searchDepth":11,"depth":11,"links":414},[],{},5,"\u002Freact\u002Fpatterns\u002Fforward-ref-imperative",[419,423,427,431,435,439,443,447,451,455,459,463,467,471,475,479,483,487,491,495],{"id":420,"difficulty":42,"q":421,"a":422},"why-no-ref-on-function-components","Why can't you pass a ref directly to a function component the same way you pass one to a DOM element?","Function components are plain functions — they have no backing instance. When React\nrenders a class component it creates an object you can point a ref at. Function\ncomponents produce nothing but JSX, so there is **no object to attach the ref to**\nby default.\n\n```jsx\nfunction Input({ value, onChange }) {\n  return \u003Cinput value={value} onChange={onChange} \u002F>\n}\n\nfunction Parent() {\n  const ref = useRef(null)\n  \u002F\u002F ❌ ref will be null; React logs a warning\n  return \u003CInput ref={ref} value=\"\" onChange={() => {}} \u002F>\n}\n```\n\nTo let a parent reach inside, you must either wrap with `React.forwardRef` (React\n≤ 18) or accept `ref` as an explicit prop (React 19+).\n\n**Rule of thumb:** \"No instance\" means \"no implicit ref\" — you must opt in explicitly.\n",{"id":424,"difficulty":42,"q":425,"a":426},"what-is-forward-ref","What does `React.forwardRef` do and what does its callback signature look like?","`React.forwardRef` wraps a render function and injects the parent-supplied ref as\na **second argument** alongside `props`. It returns a component that React treats\nas a normal component but also honours the ref.\n\n```jsx\nimport { forwardRef } from 'react'\n\n\u002F\u002F forwardRef(renderFn) — renderFn receives (props, ref)\nconst FancyInput = forwardRef(function FancyInput(props, ref) {\n  return (\n    \u003Cinput\n      ref={ref}          \u002F\u002F wire the forwarded ref to the DOM node\n      className=\"fancy\"\n      {...props}\n    \u002F>\n  )\n})\n\n\u002F\u002F Parent\nfunction Form() {\n  const inputRef = useRef(null)\n  return (\n    \u003C>\n      \u003CFancyInput ref={inputRef} placeholder=\"Type here\" \u002F>\n      \u003Cbutton onClick={() => inputRef.current.focus()}>Focus\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\nWithout `forwardRef`, `ref` would not appear in the render function's argument list\nat all — it is filtered out of `props` by React's reconciler.\n\n**Rule of thumb:** `forwardRef` = \"please pass the ref through to me as arg #2.\"\n",{"id":428,"difficulty":34,"q":429,"a":430},"what-is-use-imperative-handle","What does `useImperativeHandle` do, and why would you use it instead of forwarding a raw DOM ref?","`useImperativeHandle(ref, createHandle, deps?)` **replaces** what the parent sees\nwhen it reads `ref.current`. Instead of the raw DOM node you expose a custom object\nwith only the methods you choose to surface. This is the controlled-API boundary\nbetween child and parent.\n\n```jsx\nconst VideoPlayer = forwardRef(function VideoPlayer({ src }, ref) {\n  const videoRef = useRef(null)\n\n  useImperativeHandle(ref, () => ({\n    \u002F\u002F expose a curated imperative API — not the raw \u003Cvideo> element\n    play()  { videoRef.current.play() },\n    pause() { videoRef.current.pause() },\n    seek(t) { videoRef.current.currentTime = t },\n  }))\n\n  return \u003Cvideo ref={videoRef} src={src} \u002F>\n})\n\nfunction Page() {\n  const player = useRef(null)\n  return (\n    \u003C>\n      \u003CVideoPlayer ref={player} src=\"\u002Fmovie.mp4\" \u002F>\n      \u003Cbutton onClick={() => player.current.play()}>Play\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\nThe parent can call `play`, `pause`, and `seek` but cannot touch the raw `\u003Cvideo>`\nnode — accidental DOM manipulation is prevented.\n\n**Rule of thumb:** `useImperativeHandle` = \"I'll expose only what I designed as my public API.\"\n",{"id":432,"difficulty":34,"q":433,"a":434},"full-pattern-combined","Write the canonical \"custom input\" that uses `forwardRef` + `useImperativeHandle` together to expose `focus`, `blur`, and `clear`.","The standard pattern: keep the real DOM ref private inside the component; expose\nonly the three operations via `useImperativeHandle`.\n\n```jsx\nimport { forwardRef, useImperativeHandle, useRef } from 'react'\n\nconst SmartInput = forwardRef(function SmartInput(props, ref) {\n  const inputRef = useRef(null)          \u002F\u002F private — not leaked to parent\n\n  useImperativeHandle(ref, () => ({\n    focus() { inputRef.current.focus() },\n    blur()  { inputRef.current.blur()  },\n    clear() { inputRef.current.value = '' },\n  }), []) \u002F\u002F no deps — handle never changes\n\n  return \u003Cinput ref={inputRef} {...props} \u002F>\n})\n\n\u002F\u002F Usage\nfunction LoginForm() {\n  const usernameRef = useRef(null)\n  return (\n    \u003C>\n      \u003CSmartInput ref={usernameRef} placeholder=\"Username\" \u002F>\n      \u003Cbutton onClick={() => usernameRef.current.clear()}>Reset\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\nNote: the `deps` array of `useImperativeHandle` works exactly like `useEffect` —\nan empty array means the handle object is created once and never recreated.\n\n**Rule of thumb:** always keep the raw DOM ref private and return only the surface area the parent actually needs.\n",{"id":436,"difficulty":34,"q":437,"a":438},"when-to-use-imperative-api","When is exposing an imperative handle appropriate, and when should you prefer props\u002Fstate instead?","Imperative handles suit **inherently imperative actions** that have no sensible\ndeclarative representation: focus management, scroll commands, starting\u002Fstopping\nmedia, triggering animations, opening\u002Fclosing portals when the open state is owned\nby the child.\n\n```jsx\n\u002F\u002F ✅ appropriate — \"start playing\" is an event, not a state the parent owns\nplayer.current.play()\n\n\u002F\u002F ✅ appropriate — programmatic focus after async validation\ninputRef.current.focus()\n\n\u002F\u002F ❌ avoid — visibility is declarative; use a prop instead\nmodalRef.current.setTitle('New title')   \u002F\u002F should be \u003CModal title={...} \u002F>\n\n\u002F\u002F ❌ avoid — data flow should go through props, not imperative setters\nlistRef.current.setItems(data)           \u002F\u002F should be \u003CList items={data} \u002F>\n```\n\nReact's model is \"data flows down via props.\" Imperative handles are the escape\nhatch for side-effectful actions that can't be expressed as a render-cycle change.\n\n**Rule of thumb:** if the parent needs to *trigger an action*, use a handle; if it needs to *change what renders*, use a prop.\n",{"id":440,"difficulty":34,"q":441,"a":442},"exposing-full-dom-vs-custom-handle","What are the trade-offs between forwarding a raw DOM ref versus exposing a custom imperative handle?","Forwarding the raw DOM ref gives the parent **full access** — convenient, but\nit couples the parent to implementation details and allows accidental mutations.\n\n```jsx\n\u002F\u002F raw DOM ref — parent can do anything, including things you don't want\nconst RawInput = forwardRef((props, ref) => \u003Cinput ref={ref} {...props} \u002F>)\n\n\u002F\u002F custom handle — parent can only call what you expose\nconst SafeInput = forwardRef((props, ref) => {\n  const inner = useRef(null)\n  useImperativeHandle(ref, () => ({\n    focus: () => inner.current.focus(),\n    \u002F\u002F getSelectionRange, scrollIntoView, etc. — only what you choose\n  }))\n  return \u003Cinput ref={inner} {...props} \u002F>\n})\n```\n\nReasons to prefer a custom handle:\n- The child may replace its DOM implementation (e.g. swap `\u003Cinput>` for a\n  contenteditable div) without breaking the parent.\n- Prevents parents from reading `value` directly, bypassing React's state.\n- Documents the intended imperative API explicitly.\n\n**Rule of thumb:** forward the raw ref for thin wrappers; use a custom handle for components with a stable public contract.\n",{"id":444,"difficulty":95,"q":445,"a":446},"typescript-forward-ref-typing","How do you correctly type a `forwardRef` component in TypeScript, including the `ref` and props generics?","`forwardRef` takes two type parameters: the **element \u002F handle type** and the\n**props type**. The order is `forwardRef\u003CHandleType, PropsType>`.\n\n```tsx\nimport { forwardRef, useRef, type ForwardedRef } from 'react'\n\ninterface InputProps {\n  label: string\n  defaultValue?: string\n}\n\n\u002F\u002F forwardRef\u003Chandle-type, props-type>\nconst LabelledInput = forwardRef\u003CHTMLInputElement, InputProps>(\n  function LabelledInput({ label, defaultValue }, ref) {\n    return (\n      \u003Clabel>\n        {label}\n        \u003Cinput ref={ref} defaultValue={defaultValue} \u002F>\n      \u003C\u002Flabel>\n    )\n  }\n)\n\n\u002F\u002F Consumer\nfunction Form() {\n  const ref = useRef\u003CHTMLInputElement>(null)\n  ref.current?.focus()   \u002F\u002F TS knows it's HTMLInputElement | null\n  return \u003CLabelledInput ref={ref} label=\"Name\" \u002F>\n}\n```\n\nIf you use `useImperativeHandle`, replace `HTMLInputElement` with your handle\ninterface (e.g. `{ focus(): void; clear(): void }`).\n\n**Rule of thumb:** `forwardRef\u003CHandleType, PropsType>` — handle first, props second.\n",{"id":448,"difficulty":95,"q":449,"a":450},"typescript-imperative-handle-typing","How do you type `useImperativeHandle` when the exposed handle is a custom interface?","Define an interface for the handle, use it as the first generic to `forwardRef`,\nand `useImperativeHandle` will enforce that `createHandle` returns a conforming\nobject.\n\n```tsx\nimport { forwardRef, useImperativeHandle, useRef } from 'react'\n\n\u002F\u002F 1. Define the public imperative API\nexport interface ModalHandle {\n  open(): void\n  close(): void\n  isOpen(): boolean\n}\n\ninterface ModalProps {\n  title: string\n  children: React.ReactNode\n}\n\n\u002F\u002F 2. Use ModalHandle as the first generic\nconst Modal = forwardRef\u003CModalHandle, ModalProps>(function Modal(\n  { title, children },\n  ref\n) {\n  const [visible, setVisible] = React.useState(false)\n\n  useImperativeHandle(ref, () => ({\n    open:   () => setVisible(true),\n    close:  () => setVisible(false),\n    isOpen: () => visible,\n  }))\n\n  if (!visible) return null\n  return \u003Cdialog open>\u003Ch2>{title}\u003C\u002Fh2>{children}\u003C\u002Fdialog>\n})\n\n\u002F\u002F 3. Parent types the ref with the handle interface\nfunction App() {\n  const modalRef = React.useRef\u003CModalHandle>(null)\n  return (\n    \u003C>\n      \u003CModal ref={modalRef} title=\"Alert\">Are you sure?\u003C\u002FModal>\n      \u003Cbutton onClick={() => modalRef.current?.open()}>Show\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\n**Rule of thumb:** export the handle interface alongside the component so consumers can type their refs without importing internals.\n",{"id":452,"difficulty":95,"q":453,"a":454},"react-19-ref-as-prop","How does React 19 change ref handling, and is `forwardRef` still needed?","In React 19, **`ref` is a regular prop**. Function components can receive `ref`\ndirectly in their props object — no `forwardRef` wrapper required. `forwardRef`\nstill works for backwards compatibility but is considered legacy and will eventually\nbe deprecated.\n\n```tsx\n\u002F\u002F React 19 — ref is just another prop\nfunction FancyInput({ ref, ...props }: React.ComponentProps\u003C'input'> & {\n  ref?: React.Ref\u003CHTMLInputElement>\n}) {\n  return \u003Cinput ref={ref} className=\"fancy\" {...props} \u002F>\n}\n\n\u002F\u002F React ≤ 18 — must use forwardRef\nconst FancyInputLegacy = React.forwardRef\u003CHTMLInputElement, React.ComponentProps\u003C'input'>>(\n  function FancyInputLegacy(props, ref) {\n    return \u003Cinput ref={ref} className=\"fancy\" {...props} \u002F>\n  }\n)\n```\n\n`useImperativeHandle` continues to work in React 19 — you still call it inside the\ncomponent with the `ref` prop directly.\n\n**Rule of thumb:** for new React 19 codebases, skip `forwardRef` and accept `ref` as a prop; keep `forwardRef` when targeting older React versions.\n",{"id":456,"difficulty":34,"q":457,"a":458},"memo-and-forward-ref","How do `React.memo` and `forwardRef` interact, and in what order should you compose them?","Both `forwardRef` and `memo` are higher-order wrappers that return a new component.\nYou must apply `forwardRef` **first** (innermost), then wrap with `memo` so that\nmemoisation sees the already-forwarded component.\n\n```jsx\nimport { forwardRef, memo, useRef } from 'react'\n\n\u002F\u002F Step 1 — enable ref forwarding\nconst BaseInput = forwardRef(function BaseInput(props, ref) {\n  return \u003Cinput ref={ref} {...props} \u002F>\n})\n\n\u002F\u002F Step 2 — memoize the forwarded component\nconst MemoInput = memo(BaseInput)\n\n\u002F\u002F Usage — both ref forwarding and memoisation work correctly\nfunction Parent() {\n  const ref = useRef(null)\n  return \u003CMemoInput ref={ref} value=\"\" onChange={() => {}} \u002F>\n}\n```\n\nIf you apply `memo` first and then `forwardRef`, the outer wrapper still works\nin practice (React resolves the chain), but the conventional and explicit order is\n`memo(forwardRef(...))`.\n\n**Rule of thumb:** `memo(forwardRef(component))` — ref first, memo second.\n",{"id":460,"difficulty":34,"q":461,"a":462},"modal-open-close-pattern","Show a real-world \"modal open\u002Fclose\" pattern where the parent triggers `open()` and `close()` imperatively.","This pattern is appropriate when the **open\u002Fclosed state lives inside the modal**\nitself (e.g. it manages its own transition) and the parent only needs to command it.\n\n```jsx\nconst ConfirmModal = forwardRef(function ConfirmModal({ onConfirm }, ref) {\n  const [open, setOpen] = React.useState(false)\n  const dialogRef = useRef(null)\n\n  useImperativeHandle(ref, () => ({\n    open:  () => { setOpen(true);  dialogRef.current?.showModal() },\n    close: () => { setOpen(false); dialogRef.current?.close()     },\n  }))\n\n  if (!open) return null\n  return (\n    \u003Cdialog ref={dialogRef}>\n      \u003Cp>Are you sure?\u003C\u002Fp>\n      \u003Cbutton onClick={() => { onConfirm(); setOpen(false) }}>Yes\u003C\u002Fbutton>\n      \u003Cbutton onClick={() => setOpen(false)}>No\u003C\u002Fbutton>\n    \u003C\u002Fdialog>\n  )\n})\n\nfunction DeleteButton({ id }) {\n  const modal = useRef(null)\n  return (\n    \u003C>\n      \u003Cbutton onClick={() => modal.current.open()}>Delete\u003C\u002Fbutton>\n      \u003CConfirmModal ref={modal} onConfirm={() => deleteItem(id)} \u002F>\n    \u003C\u002F>\n  )\n}\n```\n\n**Rule of thumb:** use this only when open\u002Fclose state is truly private to the modal; if the parent must know whether the modal is open, lift state or use a prop instead.\n",{"id":464,"difficulty":42,"q":465,"a":466},"focus-management-pattern","Demonstrate using `forwardRef` for focus management in a form with multiple inputs.","Focus management is the canonical use case — moving focus programmatically after\nvalidation errors or submit actions.\n\n```jsx\nconst Field = forwardRef(function Field({ label, error, ...inputProps }, ref) {\n  return (\n    \u003Cdiv className={error ? 'field field--error' : 'field'}>\n      \u003Clabel>{label}\u003C\u002Flabel>\n      \u003Cinput ref={ref} {...inputProps} \u002F>\n      {error && \u003Cspan className=\"error\">{error}\u003C\u002Fspan>}\n    \u003C\u002Fdiv>\n  )\n})\n\nfunction SignupForm() {\n  const emailRef    = useRef(null)\n  const passwordRef = useRef(null)\n\n  function handleSubmit(e) {\n    e.preventDefault()\n    const errors = validate(e.target)\n    if (errors.email)    { emailRef.current.focus();    return }\n    if (errors.password) { passwordRef.current.focus(); return }\n    submitForm(e.target)\n  }\n\n  return (\n    \u003Cform onSubmit={handleSubmit}>\n      \u003CField ref={emailRef}    label=\"Email\"    type=\"email\"    \u002F>\n      \u003CField ref={passwordRef} label=\"Password\" type=\"password\" \u002F>\n      \u003Cbutton type=\"submit\">Sign up\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n```\n\n**Rule of thumb:** reach for `forwardRef` when a parent orchestrates focus across several child inputs after async feedback.\n",{"id":468,"difficulty":95,"q":469,"a":470},"animation-handle-pattern","How would you expose animation controls (play, pause, reset) from a child component via `useImperativeHandle`?","Animation libraries (GSAP, Framer Motion) maintain internal timelines. Exposing\n`play`, `pause`, and `reset` via a handle keeps the animation logic encapsulated\nwhile giving parent components a clean trigger surface.\n\n```jsx\nimport gsap from 'gsap'\n\nconst AnimatedCard = forwardRef(function AnimatedCard({ children }, ref) {\n  const cardRef = useRef(null)\n  const tlRef   = useRef(null)         \u002F\u002F private timeline\n\n  useEffect(() => {\n    tlRef.current = gsap.timeline({ paused: true })\n      .fromTo(cardRef.current,\n        { opacity: 0, y: 40 },\n        { opacity: 1, y: 0, duration: 0.4 }\n      )\n  }, [])\n\n  useImperativeHandle(ref, () => ({\n    play:  () => tlRef.current.play(),\n    pause: () => tlRef.current.pause(),\n    reset: () => tlRef.current.restart().pause(),\n  }))\n\n  return \u003Cdiv ref={cardRef}>{children}\u003C\u002Fdiv>\n})\n\nfunction Demo() {\n  const card = useRef(null)\n  return (\n    \u003C>\n      \u003CAnimatedCard ref={card}>Hello\u003C\u002FAnimatedCard>\n      \u003Cbutton onClick={() => card.current.play()}>Animate in\u003C\u002Fbutton>\n    \u003C\u002F>\n  )\n}\n```\n\n**Rule of thumb:** expose semantic action names (`play`, `pause`) not raw library handles — the parent shouldn't need to know which animation library you use.\n",{"id":472,"difficulty":95,"q":473,"a":474},"forwarded-ref-type-forwarded-ref","What is `ForwardedRef\u003CT>` in TypeScript and when do you need it over `Ref\u003CT>`?","`React.ForwardedRef\u003CT>` is the exact type of the second argument received by a\n`forwardRef` render function. It is a union: `RefCallback\u003CT> | MutableRefObject\u003CT> | null`.\n`React.Ref\u003CT>` is a wider union that also includes `string` refs (legacy) and is\nused for *passing* refs to elements.\n\n```tsx\nimport { forwardRef, type ForwardedRef } from 'react'\n\n\u002F\u002F ForwardedRef\u003CT> is correct for the parameter you *receive*\nfunction BaseInput(\n  props: React.ComponentProps\u003C'input'>,\n  ref: ForwardedRef\u003CHTMLInputElement>  \u002F\u002F not Ref\u003C> — this is what forwardRef gives you\n) {\n  return \u003Cinput ref={ref} {...props} \u002F>\n}\nexport default forwardRef(BaseInput)\n\n\u002F\u002F If you want to accept a ref in a helper that isn't a forwardRef component:\nfunction mergeRefs\u003CT>(...refs: ForwardedRef\u003CT>[]): React.RefCallback\u003CT> {\n  return (node) => {\n    refs.forEach(ref => {\n      if (typeof ref === 'function') ref(node)\n      else if (ref) ref.current = node\n    })\n  }\n}\n```\n\n**Rule of thumb:** use `ForwardedRef\u003CT>` for the ref parameter inside `forwardRef`; use `Ref\u003CT>` or `RefObject\u003CT>` in props interfaces for refs the component *accepts* as props.\n",{"id":476,"difficulty":34,"q":477,"a":478},"testing-forward-ref-components","How do you test a `forwardRef` component that exposes an imperative handle in React Testing Library?","Use `React.createRef()` (or `useRef` inside a wrapper component) to capture the\nhandle, then assert on its methods.\n\n```jsx\nimport { render, screen } from '@testing-library\u002Freact'\nimport userEvent from '@testing-library\u002Fuser-event'\nimport { createRef } from 'react'\nimport SmartInput from '.\u002FSmartInput'\n\ntest('clear() empties the input', async () => {\n  const ref = createRef()\n  render(\u003CSmartInput ref={ref} defaultValue=\"hello\" data-testid=\"inp\" \u002F>)\n\n  \u002F\u002F verify initial state\n  expect(screen.getByTestId('inp').value).toBe('hello')\n\n  \u002F\u002F call the imperative method\n  ref.current.clear()\n\n  \u002F\u002F assert DOM changed\n  expect(screen.getByTestId('inp').value).toBe('')\n})\n\ntest('focus() moves focus to the input', () => {\n  const ref = createRef()\n  render(\u003CSmartInput ref={ref} data-testid=\"inp\" \u002F>)\n  ref.current.focus()\n  expect(screen.getByTestId('inp')).toHaveFocus()\n})\n```\n\nYou don't need to test the internal DOM structure — only that the exposed handle\nmethods produce the expected observable behaviour.\n\n**Rule of thumb:** test the contract of the handle (what it does), not how it is implemented.\n",{"id":480,"difficulty":34,"q":481,"a":482},"deps-array-use-imperative-handle","When should you provide a non-empty `deps` array to `useImperativeHandle`, and what happens if you omit it?","`useImperativeHandle(ref, createHandle, deps)` re-runs `createHandle` whenever a\ndependency changes, replacing `ref.current` with a new object. With an empty array\n`[]`, the handle is created once. With no deps array at all, it reruns on every render.\n\n```jsx\nconst Counter = forwardRef(function Counter(props, ref) {\n  const [count, setCount] = useState(0)\n\n  useImperativeHandle(ref, () => ({\n    increment: () => setCount(c => c + 1),\n    \u002F\u002F getCount captures the current count via closure —\n    \u002F\u002F must be in deps so the handle refreshes when count changes\n    getCount:  () => count,\n  }), [count]) \u002F\u002F ← re-create handle when count changes\n\n  return \u003Cp>{count}\u003C\u002Fp>\n})\n```\n\nIf `getCount` were in a stale closure (deps omitted or `[]`) it would always return\nthe initial value. Omitting deps entirely causes a new handle object every render,\nwhich is wasteful but not incorrect.\n\n**Rule of thumb:** include any state or prop that the handle methods read via closure; use `[]` only when the methods rely solely on refs or setters (which are stable).\n",{"id":484,"difficulty":95,"q":485,"a":486},"multiple-refs-same-element","How do you support both a forwarded ref and an internal ref pointing at the same DOM node — the \"mergeRefs\" pattern?","A DOM node can only have one `ref` prop. When a component needs its own local ref\n*and* must forward the parent's ref to the same node, you merge them with a\ncallback ref.\n\n```jsx\nfunction mergeRefs(...refs) {\n  return (node) => {\n    refs.forEach(ref => {\n      if (typeof ref === 'function') ref(node)      \u002F\u002F callback ref\n      else if (ref != null) ref.current = node      \u002F\u002F object ref\n    })\n  }\n}\n\nconst ScrollableList = forwardRef(function ScrollableList(props, forwardedRef) {\n  const localRef = useRef(null)  \u002F\u002F needed for internal scroll logic\n\n  function scrollToTop() {\n    localRef.current?.scrollTo({ top: 0, behavior: 'smooth' })\n  }\n\n  return (\n    \u003Cul\n      ref={mergeRefs(localRef, forwardedRef)} \u002F\u002F both refs point at \u003Cul>\n      {...props}\n    \u002F>\n  )\n})\n```\n\nLibraries like `useMergedRef` (react-merge-refs) do exactly this. React 19's\ncleanup-returning ref callbacks make the pattern cleaner still.\n\n**Rule of thumb:** when you need two refs on one node, always merge — never pick one and lose the other.\n",{"id":488,"difficulty":34,"q":489,"a":490},"avoid-imperative-anti-patterns","What are the most common mistakes developers make when using `forwardRef` and `useImperativeHandle`?","Five common mistakes:\n\n1. **Exposing the raw DOM node when a custom handle is safer** — gives the parent\n   unrestricted access.\n2. **Using an imperative handle to pass data** — `ref.current.getUser()` should be\n   `const { user } = useUser()` or a prop.\n3. **Forgetting to memoize the handle** when it closes over frequently-changing\n   state without listing it in deps.\n4. **Wrapping every component in `forwardRef`** \"just in case\" — most components\n   are controlled via props and don't need a ref at all.\n5. **Not cleaning up** — if the handle exposes subscriptions or timers, they should\n   be cleared in a `useEffect` cleanup, not in the handle method itself.\n\n```jsx\n\u002F\u002F ❌ anti-pattern — data fetch through an imperative handle\nconst DataList = forwardRef((_, ref) => {\n  useImperativeHandle(ref, () => ({\n    getData: async () => fetchData(),  \u002F\u002F parent should just receive data as a prop\n  }))\n  return \u003Cul \u002F>\n})\n\n\u002F\u002F ✅ prefer — data flows through props \u002F context\nfunction DataList({ data }) {\n  return \u003Cul>{data.map(item => \u003Cli key={item.id}>{item.name}\u003C\u002Fli>)}\u003C\u002Ful>\n}\n```\n\n**Rule of thumb:** before adding an imperative handle, ask \"can I achieve this with a prop, callback, or state?\" — if yes, do that instead.\n",{"id":492,"difficulty":42,"q":493,"a":494},"display-name-forward-ref","How do you set a meaningful display name on a `forwardRef` component for React DevTools?","React DevTools shows the display name in the component tree. Anonymous `forwardRef`\ncalls appear as `ForwardRef` — unhelpful for debugging.\n\n```jsx\n\u002F\u002F Option 1 — named function expression (preferred)\nconst TextInput = forwardRef(function TextInput(props, ref) {\n  return \u003Cinput ref={ref} {...props} \u002F>\n})\n\u002F\u002F DevTools shows: TextInput\n\n\u002F\u002F Option 2 — set displayName explicitly\nconst TextInput2 = forwardRef((props, ref) => (\n  \u003Cinput ref={ref} {...props} \u002F>\n))\nTextInput2.displayName = 'TextInput'\n\n\u002F\u002F Option 3 — in a factory helper, set displayName dynamically\nfunction createForwardedInput(displayName) {\n  const C = forwardRef((props, ref) => \u003Cinput ref={ref} {...props} \u002F>)\n  C.displayName = displayName\n  return C\n}\n```\n\nNamed function expressions (Option 1) are the cleanest because the name is\ninferred automatically without an extra line.\n\n**Rule of thumb:** always use a named function inside `forwardRef` — you get a readable DevTools tree for free.\n",{"id":496,"difficulty":34,"q":497,"a":498},"scroll-into-view-pattern","How would you implement a `scrollIntoView()` imperative handle to let a parent scroll a child list item into view?","A list component that manages its own DOM can expose a `scrollTo(index)` method\nso the parent doesn't have to reach into its internals.\n\n```jsx\nconst VirtualList = forwardRef(function VirtualList({ items }, ref) {\n  const rowRefs = useRef([])   \u002F\u002F array of row DOM nodes\n\n  useImperativeHandle(ref, () => ({\n    \u002F\u002F scrollTo(index) — brings row at `index` into the viewport\n    scrollTo(index) {\n      rowRefs.current[index]?.scrollIntoView({\n        behavior: 'smooth',\n        block: 'nearest',\n      })\n    },\n  }), []) \u002F\u002F stable — no deps needed; rowRefs.current is mutable\n\n  return (\n    \u003Cul>\n      {items.map((item, i) => (\n        \u003Cli key={item.id} ref={el => { rowRefs.current[i] = el }}>\n          {item.label}\n        \u003C\u002Fli>\n      ))}\n    \u003C\u002Ful>\n  )\n})\n\nfunction SearchResults({ results, activeIndex }) {\n  const listRef = useRef(null)\n  useEffect(() => {\n    listRef.current?.scrollTo(activeIndex)\n  }, [activeIndex])\n\n  return \u003CVirtualList ref={listRef} items={results} \u002F>\n}\n```\n\n**Rule of thumb:** when the child owns a collection of DOM nodes, expose a semantic `scrollTo(index)` rather than exposing the raw refs array.\n",{"description":32},"React forwardRef and useImperativeHandle interview questions — ref forwarding, imperative API design, focus control, animation handles, and TypeScript ref typing.","react\u002Fpatterns\u002Fforward-ref-imperative","forwardRef & useImperativeHandle","3l-TC_wGYc6rODTadiYbBCLWtDVvE0FvoJi49qa5mBg",1782244096729]