Question presented to candidate:
"A component tree re-renders too much. Before you reach for memo and useCallback everywhere, what would you try structurally?"
What a strong answer should cover:
- The mechanism: React bails out of re-rendering a subtree when the element object is referentially identical to the previous render. An element passed in as
childrenis created by an ancestor that did not re-render, so it is identical. - Two structural moves: lift content up (pass the expensive subtree as
children) and move state down (isolate the state into the smallest component that needs it). - Why this beats memoisation: no dependency arrays to get wrong, no
useCallbackchains, nothing to keep in sync as the code changes. memois fragile because it depends on every prop staying referentially stable; one inline object silently defeats it.- The important limitation: lifting content up only helps when the state lives in the component receiving children, not in an ancestor of it.
- Where memoisation is still the right tool: long lists, expensive derived values, and props that genuinely must be objects.
- The React Compiler changes the calculus for memoisation but not for composition — structure still matters.
Clarifying questions expected:
- "Where does the state that triggers these renders actually live?"
- "Have we profiled, and is the re-render actually expensive, or just frequent?"
Code / implementation expected: Yes — the lift-content-up refactor, ideally with visible render counts.