[{"data":1,"prerenderedAt":112},["ShallowReactive",2],{"qa-\u002Freact\u002Frendering-and-performance\u002Freact-memo":3},{"page":4,"siblings":91,"blog":109},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":20,"order":12,"path":21,"questions":22,"questionsCount":81,"related":82,"seo":83,"seoDescription":84,"stem":85,"subtopic":86,"topic":87,"topicSlug":88,"updated":89,"__hash__":90},"qa\u002Freact\u002Frendering-and-performance\u002Freact-memo.md","React Memo",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","React","react",{"subtopicSlug":19},"react-memo",true,"\u002Freact\u002Frendering-and-performance\u002Freact-memo",[23,28,32,36,40,44,48,53,57,61,65,69,73,77],{"id":24,"difficulty":25,"q":26,"a":27},"what-is-react-memo","easy","What does React.memo do?","`React.memo` is a **higher-order component** that wraps a function component\nand skips re-rendering it when its props are shallowly equal to the previous\nrender's props.\n\n```jsx\nconst Button = React.memo(function Button({ label, onClick }) {\n  console.log('render')\n  return \u003Cbutton onClick={onClick}>{label}\u003C\u002Fbutton>\n})\n\n\u002F\u002F Parent re-renders with same label and onClick reference:\n\u002F\u002F → Button's console.log does NOT fire\n```\n\nUnder the hood, before calling your component function React compares each\nold prop to each new prop with `Object.is`. If all are equal, it reuses the\nprevious render output.\n\n`React.memo` only applies to function components. The class-component\nequivalent is `PureComponent` (or `shouldComponentUpdate`).\n\n**Rule of thumb:** `React.memo` is a performance hint, not a correctness\nguarantee — React may still re-render the component in some cases (e.g.,\nconcurrent rendering). Never rely on it to prevent side effects from firing.\n",{"id":29,"difficulty":25,"q":30,"a":31},"shallow-equality-explained","What is shallow equality and why does it matter for React.memo?","**Shallow equality** compares values one level deep using `Object.is`:\nprimitives are compared by value; objects and functions are compared by\n**reference**.\n\n```js\nObject.is(1, 1)           \u002F\u002F true  — same primitive\nObject.is('a', 'a')       \u002F\u002F true  — same primitive\nObject.is([], [])         \u002F\u002F false — different object references\nObject.is({ x: 1 }, { x: 1 }) \u002F\u002F false — different object references\n```\n\nThis is why inline objects and functions as props break memoisation:\n\n```jsx\n\u002F\u002F BAD: new object on every render → memo always re-renders\n\u003CChart options={{ color: 'red' }} \u002F>\n\n\u002F\u002F GOOD: stable reference, memo works\nconst OPTIONS = { color: 'red' }\n\u003CChart options={OPTIONS} \u002F>\n\n\u002F\u002F GOOD: memoised object\nconst options = useMemo(() => ({ color }), [color])\n\u003CChart options={options} \u002F>\n```\n\n**Rule of thumb:** Pass primitives when possible; stabilise object and\nfunction props with `useMemo` \u002F `useCallback` when using `React.memo`.\n",{"id":33,"difficulty":14,"q":34,"a":35},"when-to-use-memo","When is React.memo actually worth using?","`React.memo` pays off when **all three** conditions hold:\n\n1. The component renders **frequently** (its parent re-renders often).\n2. The component renders **expensively** (large subtree, heavy computation).\n3. Its **props are stable** (primitives or memoised references).\n\n```jsx\n\u002F\u002F Worth memoising: renders on every keystroke, large list\nconst ResultList = React.memo(function ResultList({ items }) {\n  return (\n    \u003Cul>\n      {items.map(item => \u003Cli key={item.id}>{item.name}\u003C\u002Fli>)}\n    \u003C\u002Ful>\n  )\n})\n\n\u002F\u002F Not worth memoising: renders rarely, trivially cheap\nconst PageTitle = React.memo(function PageTitle({ text }) {\n  return \u003Ch1>{text}\u003C\u002Fh1>\n})\n```\n\nThe overhead of `React.memo` itself (the shallow comparison on every parent\nrender) can exceed the savings if the component is cheap or its props are\nunstable objects.\n\n**Rule of thumb:** Profile first. Reach for `React.memo` only when the\nProfiler shows the component actually re-renders unnecessarily and the\nre-render is measurably expensive.\n",{"id":37,"difficulty":14,"q":38,"a":39},"custom-comparator","How do you use a custom comparator with React.memo?","Pass a second argument to `React.memo`: a function that receives the\n**previous and next props** and returns `true` if the component should\n*skip* re-rendering (i.e., they are \"equal enough\").\n\n```jsx\nconst Chart = React.memo(\n  function Chart({ data, width }) {\n    return \u003Ccanvas ref={drawChart(data, width)} \u002F>\n  },\n  (prevProps, nextProps) => {\n    \u002F\u002F Skip re-render if only the data length changed, not actual values\n    return (\n      prevProps.width === nextProps.width &&\n      prevProps.data.length === nextProps.data.length &&\n      prevProps.data.every((v, i) => v === nextProps.data[i])\n    )\n  }\n)\n```\n\nImportant: returning `true` means **do NOT re-render** (the opposite of\n`shouldComponentUpdate`, which returns `true` to allow a re-render). This\nis a common source of confusion.\n\n**Rule of thumb:** Custom comparators add complexity and can silently\nsuppress needed updates if written incorrectly. Use them only when the\ndefault shallow comparison is measurably too eager.\n",{"id":41,"difficulty":14,"q":42,"a":43},"memo-pitfall-inline-functions","Why do inline function props break React.memo, and how do you fix it?","Each render creates a **new function object**, so the reference changes\nevery time, causing `React.memo`'s shallow comparison to always return\n\"not equal\" and re-render anyway.\n\n```jsx\nfunction Parent() {\n  const [count, setCount] = useState(0)\n\n  \u002F\u002F New function reference on every Parent render → memo useless\n  return \u003CChild onClick={() => console.log('click')} \u002F>\n}\n\nconst Child = React.memo(function Child({ onClick }) {\n  console.log('Child render') \u002F\u002F still fires every time\n  return \u003Cbutton onClick={onClick}>Click\u003C\u002Fbutton>\n})\n```\n\nFix with `useCallback` to stabilise the reference:\n\n```jsx\nfunction Parent() {\n  const [count, setCount] = useState(0)\n\n  const handleClick = useCallback(() => {\n    console.log('click')\n  }, []) \u002F\u002F stable reference — same function object across renders\n\n  return \u003CChild onClick={handleClick} \u002F>\n}\n```\n\n**Rule of thumb:** `React.memo` and `useCallback` are best friends — you\nalmost always need both: memo to skip the child render, and useCallback to\nprevent the function prop from busting the memo.\n",{"id":45,"difficulty":25,"q":46,"a":47},"memo-vs-purecomponent","What is the difference between React.memo and PureComponent?","Both perform a **shallow prop comparison** to avoid unnecessary re-renders,\nbut they apply to different component types.\n\n| | `React.memo` | `PureComponent` |\n|---|---|---|\n| Works with | Function components | Class components |\n| Custom equality | 2nd argument comparator | Override `shouldComponentUpdate` |\n| Checks state | No (state is inside the hook, not a prop) | Yes — shallow-compares both `props` and `state` |\n\n```jsx\n\u002F\u002F Function component\nconst Foo = React.memo(function Foo(props) { … })\n\n\u002F\u002F Class component\nclass Foo extends React.PureComponent {\n  render() { … }\n}\n```\n\n`PureComponent` also shallow-compares `this.state`, which `React.memo`\nhas no equivalent for (state is internal to hooks and React itself handles\nbailing out when the state reference doesn't change).\n\n**Rule of thumb:** In modern React (function components), `React.memo` is the\nstandard tool. `PureComponent` is for legacy class components.\n",{"id":49,"difficulty":50,"q":51,"a":52},"memo-context-caveat","hard","Does React.memo prevent re-renders caused by context changes?","**No.** `React.memo` only skips re-renders caused by changed *props*.\nIf a memoised component subscribes to a context (via `useContext`) and\nthe context value changes, the component **will re-render** regardless\nof whether its props changed.\n\n```jsx\nconst ThemeContext = createContext('light')\n\nconst Card = React.memo(function Card({ title }) {\n  const theme = useContext(ThemeContext) \u002F\u002F subscribed to context\n  return \u003Cdiv className={theme}>{title}\u003C\u002Fdiv>\n})\n\n\u002F\u002F Parent provides a new context value:\n\u002F\u002F Card re-renders even though `title` prop didn't change\n```\n\nMitigation strategies:\n- Split context into multiple smaller contexts so unrelated consumers\n  don't re-render.\n- Use `useMemo` inside the component to memoize the expensive derived\n  output, even if render is called.\n- Use a state-management library (Zustand, Jotai) that uses selectors to\n  subscribe only to the slice of state a component needs.\n\n**Rule of thumb:** `React.memo` and context subscriptions are orthogonal —\nto limit context-driven re-renders you need to narrow the context or use\nselectors, not memo.\n",{"id":54,"difficulty":50,"q":55,"a":56},"memo-children-prop","Why does passing children as a prop often break React.memo?","When you write `\u003CWrapper>\u003CChild \u002F>\u003C\u002FWrapper>`, React creates a new element\nobject for `\u003CChild \u002F>` **on every render of the parent** where the JSX\nlives. Because element objects are new references each time, `React.memo`'s\nshallow comparison sees a changed `children` prop and re-renders.\n\n```jsx\nfunction Parent() {\n  const [count, setCount] = useState(0)\n\n  \u002F\u002F New \u003Cdiv>Hello\u003C\u002Fdiv> element object created every render\n  return \u003CWrapper>{\u003Cdiv>Hello\u003C\u002Fdiv>}\u003C\u002FWrapper>\n}\n\nconst Wrapper = React.memo(function Wrapper({ children }) {\n  console.log('Wrapper render') \u002F\u002F fires on every Parent re-render!\n  return \u003Csection>{children}\u003C\u002Fsection>\n})\n```\n\nFixes:\n1. Move the children JSX outside the re-rendering parent (lift it up).\n2. Wrap children in `useMemo` if they depend on parent state.\n3. Restructure so `Wrapper` doesn't need to be memoised.\n\n**Rule of thumb:** Memoising components that accept `children` is often\ncounter-productive — consider memoising the children themselves instead, or\nrethinking the component hierarchy.\n",{"id":58,"difficulty":14,"q":59,"a":60},"when-not-to-memo","When should you NOT use React.memo?","Avoid `React.memo` when:\n\n1. **Props change on every render anyway** — memo runs the comparison but\n   still re-renders, adding overhead for zero gain.\n2. **The component is trivially cheap** — shallow-comparing many props can\n   cost more than just running the component.\n3. **Props include non-stabilised objects or functions** — memo is\n   immediately defeated and the comparison is wasted work.\n4. **You haven't profiled** — premature memoisation clutters the code and\n   makes it harder to refactor.\n\n```jsx\n\u002F\u002F No point memoising — title is a new string computed in parent every render\nconst Title = React.memo(({ title }) => \u003Ch1>{title}\u003C\u002Fh1>)\n\nfunction Parent({ user }) {\n  return \u003CTitle title={`Hello, ${user.name}!`} \u002F> \u002F\u002F new string each render\n}\n```\n\n**Rule of thumb:** Reach for `React.memo` only after the Profiler confirms\na component re-renders unnecessarily AND that the re-render is expensive.\nDefault to no memoisation.\n",{"id":62,"difficulty":25,"q":63,"a":64},"memo-display-name","How do you preserve the display name of a memoised component for debugging?","When you wrap an anonymous function, React DevTools shows the component as\n`Memo` or `Anonymous`, making the component tree hard to read. Two ways to\npreserve the name:\n\n```jsx\n\u002F\u002F Option 1: named function expression (recommended)\nconst Button = React.memo(function Button({ label }) {\n  return \u003Cbutton>{label}\u003C\u002Fbutton>\n})\n\u002F\u002F DevTools shows: Memo(Button)\n\n\u002F\u002F Option 2: set displayName explicitly\nconst Button = React.memo(({ label }) => \u003Cbutton>{label}\u003C\u002Fbutton>)\nButton.displayName = 'Button'\n\n\u002F\u002F Option 3: extract and export the inner component\nfunction ButtonBase({ label }) { return \u003Cbutton>{label}\u003C\u002Fbutton> }\nexport const Button = React.memo(ButtonBase)\n```\n\n**Rule of thumb:** Always use a named function expression as the first\nargument to `React.memo` — it's the simplest and least error-prone way to\nkeep DevTools readable.\n",{"id":66,"difficulty":14,"q":67,"a":68},"forwardRef-with-memo","How do you combine React.memo with forwardRef?","Wrap with both — the order is `React.memo(React.forwardRef(...))`.\n`forwardRef` should be the inner wrapper because it transforms the\n`(props, ref)` signature; `memo` wraps the result.\n\n```jsx\nimport { forwardRef, memo } from 'react'\n\nconst FancyInput = memo(\n  forwardRef(function FancyInput({ label }, ref) {\n    return (\n      \u003Clabel>\n        {label}\n        \u003Cinput ref={ref} \u002F>\n      \u003C\u002Flabel>\n    )\n  })\n)\n\n\u002F\u002F Usage:\nconst inputRef = useRef()\n\u003CFancyInput ref={inputRef} label=\"Name\" \u002F>\ninputRef.current.focus()\n```\n\nDevTools will show: `Memo(ForwardRef(FancyInput))`.\n\n**Rule of thumb:** Compose in the order `memo(forwardRef(fn))` — memo on\nthe outside handles the prop comparison; forwardRef on the inside handles\nthe ref plumbing.\n",{"id":70,"difficulty":14,"q":71,"a":72},"class-shouldcomponentupdate","How does shouldComponentUpdate relate to React.memo?","`shouldComponentUpdate(nextProps, nextState)` is the class-component\nlifecycle that lets you control whether a component re-renders. Returning\n`false` skips the render; returning `true` allows it.\n\n`React.memo` is the functional-component analogue that handles the same\noptimisation for props only (it has no access to internal state, which React\nmanages automatically).\n\n```jsx\n\u002F\u002F Class component\nclass List extends React.Component {\n  shouldComponentUpdate(nextProps) {\n    return nextProps.items !== this.props.items \u002F\u002F custom check\n  }\n  render() { … }\n}\n\n\u002F\u002F Equivalent with function component + memo\nconst List = React.memo(\n  function List({ items }) { … },\n  (prev, next) => prev.items === next.items \u002F\u002F same semantics, inverted return\n)\n```\n\nKey difference: `shouldComponentUpdate` returning `false` skips the update;\nmemo's comparator returning `true` skips the update (inverted meaning).\n\n**Rule of thumb:** In new code, prefer function components with `React.memo`.\nUse `shouldComponentUpdate` only when maintaining or extending legacy class\ncomponents.\n",{"id":74,"difficulty":14,"q":75,"a":76},"memo-in-lists","When is it beneficial to memoize items inside a large list?","When a list contains many items and the parent state changes frequently\n(e.g., a filter input), each item component gets re-rendered on every\nkeystroke even if its own data hasn't changed. Memoising the item component\nkeeps only the changed item rendering.\n\n```jsx\n\u002F\u002F Without memo: all 1000 items re-render on every keystroke\nfunction ItemRow({ item }) {\n  return \u003Ctr>\u003Ctd>{item.name}\u003C\u002Ftd>\u003Ctd>{item.price}\u003C\u002Ftd>\u003C\u002Ftr>\n}\n\n\u002F\u002F With memo: only items whose props changed re-render\nconst ItemRow = React.memo(function ItemRow({ item }) {\n  return \u003Ctr>\u003Ctd>{item.name}\u003C\u002Ftd>\u003Ctd>{item.price}\u003C\u002Ftd>\u003C\u002Ftr>\n})\n\n\u002F\u002F Parent\nfunction Table({ rows }) {\n  return (\n    \u003Ctbody>\n      {rows.map(row => \u003CItemRow key={row.id} item={row} \u002F>)}\n    \u003C\u002Ftbody>\n  )\n}\n```\n\nFor this to work, `rows` elements must be stable references — if the parent\nrebuilds the array on every render, each `item` prop is a new object and\nmemo is defeated. Stabilise with `useMemo`.\n\n**Rule of thumb:** For large lists (50+ items) where individual items are\npure, `React.memo` on the row component is one of the highest-ROI\noptimisations you can make.\n",{"id":78,"difficulty":50,"q":79,"a":80},"memo-hot-path-cost","What is the cost of React.memo on a hot render path?","On every parent render, React must:\n\n1. Look up the previous props object for the memoised child.\n2. Run `Object.is` on every prop pair (or your custom comparator).\n3. Either skip the child render (if equal) or proceed (if not).\n\nFor a component with many props or complex prop objects, step 2 can be\nnon-trivial — especially if the comparator does deep equality or array\niteration.\n\n```jsx\n\u002F\u002F 20 props, comparator runs 20 Object.is calls on every parent render\nconst HeavyCard = React.memo(function HeavyCard({\n  id, title, description, imageUrl, price, rating,\n  inStock, category, tags, author, createdAt, updatedAt,\n  onClick, onHover, onFocus, isSelected, isFeatured,\n  discount, currency, locale\n}) { … })\n```\n\nIf the child renders in \u003C1 ms and the parent re-renders infrequently, the\nmemo overhead (prop comparison) may cost more than the render it prevents.\n\n**Rule of thumb:** Memoize components with few, stable-typed props. For\ncomponents with many props, the comparison cost can rival the render cost —\nmeasure before committing.\n",14,null,{"description":11},"React.memo interview questions — when to memoize components, shallow equality, custom comparators, pitfalls, and when memo actually hurts performance.","react\u002Frendering-and-performance\u002Freact-memo","React.memo","Rendering and Performance","rendering-and-performance","2026-06-24","7dofqRhUk6xgXgzdBuqwdmg_ndP3khxTUKeZGWjyTnY",[92,96,97,101,105],{"subtopic":93,"path":94,"order":95},"Virtual DOM and Reconciliation","\u002Freact\u002Frendering-and-performance\u002Fvirtual-dom-reconciliation",1,{"subtopic":86,"path":21,"order":12},{"subtopic":98,"path":99,"order":100},"useMemo and useCallback Patterns","\u002Freact\u002Frendering-and-performance\u002Fusememo-usecallback-patterns",3,{"subtopic":102,"path":103,"order":104},"Code Splitting and Lazy Loading","\u002Freact\u002Frendering-and-performance\u002Fcode-splitting-lazy",4,{"subtopic":106,"path":107,"order":108},"Suspense and Concurrent Rendering","\u002Freact\u002Frendering-and-performance\u002Fsuspense-concurrent",5,{"path":110,"title":111},"\u002Fblog\u002Freact-memo-guide","React.memo — A Complete Guide with Examples",1782244101001]