Question presented to candidate: "Walk me through the ways data moves between components in React — parent to child, child to parent, and between two siblings."
What a strong answer should cover:
- Parent to child: props. The default, and read-only.
- Child to parent: a callback passed down as a prop. Data still flows one way; the child invokes a function it was given.
- Sibling to sibling: lift state up to the nearest common ancestor and pass it down to both.
- Deep trees: Context, to avoid prop drilling — but note it is not a state manager, and every consumer re-renders when the value changes.
- Genuinely global or server state: a store (Redux, Zustand, Jotai) or a data library (TanStack Query, SWR). Server state is a different problem from UI state.
- Composition (
children) as the underrated alternative to Context — often it removes the drilling entirely without any new machinery. - The judgement point: choose the narrowest mechanism that works; reaching for Context or Redux too early is the common mistake.
- Refs and imperative handles exist for the rare escape-hatch case.
Clarifying questions expected:
- "How far apart are these components in the tree?"
- "Is this server data or UI state?" — they call for different tools.
- "How often does it change?" — a frequently-changing Context value is a performance problem.
Code / implementation expected: Yes — lifting state up between two siblings is the canonical thing to write.