React Curriculum

Output Traps: Effect Order, Cleanups & StrictMode

Medium100% Free~20 mins#react#output-prediction#useeffect#execution-order#cleanups#lifecycle
Interview Answer (30-Second Summary)

In a parent-child React tree, render phases execute top-down (parent before child), but commit passive effects execute bottom-up (children effects run before parent effects). When dependencies change, previous effect cleanups run before new effects execute.

Key Learning Objectives
✓

Predict the exact execution order of useEffect across nested parent-child component trees.

✓

Explain why child effects run BEFORE parent effects during the commit passive effects phase.

✓

Analyze cleanup timing: previous effect cleanup runs before subsequent effect invocation.

✓

Explain why React 18 StrictMode runs effects twice on initial mount in development.

The Interview Problem & Context

Predict the exact console output when a Parent component containing a Child component mounts, and then the Child unmounts.

1// Simulating React component tree effect order
2function simulateEffectLifecycle() {
3 const log: string[] = [];
4
5 // Mount Phase:
6 // Render phase goes top-down: Parent renders -> Child renders
7 // Commit passive effects phase goes bottom-up (post-order):
8 // 1. Child useEffect runs first!
9 log.push('child-effect');
10
11 // 2. Parent useEffect runs second!
12 log.push('parent-effect');
13
14 // Unmount / Dependency Change Phase:
15 // 3. Child cleanup runs when unmounted or before re-running!
16 log.push('child-cleanup');
17
18 return log.join(' ');
19}
20
21console.log(simulateEffectLifecycle());
Predict Console & Render Output
A

child-effect parent-effect child-cleanup

B

parent-effect child-effect child-cleanup

C

child-cleanup child-effect parent-effect

D

parent-effect child-cleanup child-effect

Execution Trace
Step 1 of 3 (Line 9)

In post-order commit traversal, Child useEffect runs before Parent useEffect.

Component / Call Stack
simulateEffectLifecycle()
Hook State & Scope
log[0]:"child-effect"
Console Output(No console logs emitted)
Deep Architectural Explanation

Why Child Effects Run Before Parent Effects

The execution of a React component tree happens in two distinct directional passes:

1. Render Phase (Top-Down Pre-Order):

  • React evaluates the root/parent component first.
  • The parent returns JSX containing children.
  • React descends into children to call their component functions.

2. Passive Effects Phase (Bottom-Up Post-Order):

  • When the commit phase finishes mutating the DOM, React walks the Fiber effect list.
  • React processes children effects first, then ascends to the parent.
  • Why this design? A parent component frequently depends on its children being fully mounted and initialized (e.g. measuring child DOM nodes or listening to child events). If parent effects ran first, child DOM nodes would not yet be ready!

3. Cleanup Timing:

  • On re-render: cleanup(oldProps) runs before effect(newProps).
  • On unmount: cleanup() runs immediately when the component leaves the tree.
Common Interview Traps & Pitfalls
✕

Assuming parent effects execute before child effects because the parent renders first.

✕

Expecting effect cleanups to run after the next effect completes.

✕

Forgetting that React 18 StrictMode in development mounts, unmounts, and remounts immediately.

Senior Interviewer Follow-Up Probes
?

How does `useEffectEvent` (experimental in React) decouple reactive dependencies from effect execution?

?

What happens if an error is thrown inside an effect cleanup function?

?

How does React schedule passive effects using MessageChannel / postMessage under the hood?

Frequently Asked Interview Questions
Why do child effects run before parent effects?

Because React traverses the Fiber tree in post-order during the commit phase, ensuring child elements are fully initialized before the parent effect runs.

When the component unmounts, and before re-executing the effect when dependencies change on subsequent renders.

To test that components handle unmounting and remounting cleanly, exposing missing cleanup functions for event listeners, subscriptions, and timers.

useLayoutEffect runs synchronously immediately after DOM mutations before browser paint. useEffect runs asynchronously after the browser paints the screen.

No. useEffect callbacks must either return a cleanup function or undefined. Returning a Promise causes an error because React expects a cleanup function.

React compares each item in the dependency array using Object.is equality with the value from the previous render pass.