HardHooks & Closures💻 Output Question

useEffect cleanup runs before next effect

💡

Hint

useEffect cleanup runs BEFORE the next effect — not when the component unmounts (unless deps=[]). Each dep change: cleanup previous → run new effect.

What does this output?

const log = [];

function simulateEffect(deps, effectFn) {
  let prevDeps = null;
  let cleanup = null;

  return function run(newDeps) {
    const changed = !prevDeps || newDeps.some((d, i) => d !== prevDeps[i]);
    if (changed) {
      if (cleanup) cleanup();       // run previous cleanup
      cleanup = effectFn() || null; // run new effect, store cleanup
      prevDeps = newDeps;
    }
  };
}

const run = simulateEffect([], () => {
  log.push('effect');
  return () => log.push('cleanup');
});

run([1]);
run([1]); // no change — nothing runs
run([2]); // cleanup old, run new
run([3]); // cleanup old, run new

console.log(log.join(','));

Correct Output

effect,cleanup,effect,cleanup,effect

Why this output?

Explanation: Run [1]: effect. Run [1] again: no change. Run [2]: cleanup from [1] fires, new effect fires. Run [3]: cleanup from [2] fires, new effect fires.

Key Insight: useEffect cleanup runs BEFORE the next effect — not when the component unmounts (unless deps=[]). Each dep change: cleanup previous → run new effect.

Practice predicting output live →

66 output questions with instant feedback

💻 Try Output Quiz