Question presented to candidate:
"You write onClick on a thousand list rows. How many DOM listeners does React attach?"
What a strong answer should cover:
- Not one per element. React uses event delegation: it attaches a small number of listeners at the root container and works out which components should receive each event.
- Since React 17 those listeners are on the root container you passed to
createRoot, not ondocument— which is what makes multiple React versions or micro-frontends on one page safe. - From that one native event React reconstructs both phases, so
onClickCapturehandlers run top-down andonClickhandlers run bottom-up, exactly like the DOM. - The observable consequence: a native
stopPropagationon the element itself prevents the React handler from ever running, because the event has to reach the container first. - Conversely,
stopPropagationinside a React handler does stop native listeners above the container, since React forwards it to the native event. - Delegation is why adding handlers to a long list is cheap, and why handler identity in JSX does not create or remove DOM listeners.
- Mixing React handlers with manually attached native listeners on the same subtree is where ordering surprises come from.
Clarifying questions expected:
- "Are we mixing in any manually attached native listeners?" — that is where the surprises live.
- "React 17 or later?" — the delegation root moved in 17.
Code / implementation expected: Optional. Demonstrating the ordering is more convincing than describing it.