- React
- Advanced Hooks, Referential Equality, and Stores
- useLayoutEffect vs useEffect vs useInsertionEffect
useLayoutEffect vs useEffect vs useInsertionEffect
useInsertionEffect runs synchronously before DOM mutations (for CSS-in-JS injection), useLayoutEffect runs synchronously after DOM mutations but before the browser paints (to measure layout and prevent visual flicker), and useEffect runs asynchronously after paint.
Key Learning Objectives
Trace the exact chronological execution order: Insertion -> DOM Mutation -> Layout -> Paint -> Passive Effects.
Prevent layout flicker when measuring DOM bounding rects and repositioning tooltips.
Understand why useInsertionEffect exists exclusively for CSS-in-JS library authors.
Recognize why useLayoutEffect blocks browser repaints and hurts performance if overused.
The Interview Problem & Context
What is logged to the console when tracing the execution sequence of useInsertionEffect, useLayoutEffect, browser paint, and useEffect for a mounted component?
1// Simulating React commit phase hook execution timeline2function simulateHookExecutionPhases() {3 const timeline: string[] = [];45 // 1. Before DOM mutations: useInsertionEffect (CSS-in-JS injection)6 timeline.push('insertion');78 // DOM mutations occur...910 // 2. Synchronous post-mutation before browser paint: useLayoutEffect11 timeline.push('layout');1213 // 3. Browser performs layout & paint to the screen14 timeline.push('paint');1516 // 4. Asynchronous passive effect after browser paint: useEffect17 timeline.push('passive');1819 return timeline.join(' ');20}2122console.log(simulateHookExecutionPhases());
Predict Console & Render Output
insertion layout paint passive
layout insertion paint passive
paint layout insertion passive
passive insertion layout paint
Execution Trace
Step 1 of 4 (Line 6)useInsertionEffect executes before any DOM mutations occur.
Deep Architectural Explanation
The Three Effect Hooks Compared
| Hook | Timing | Purpose |
|---|---|---|
useInsertionEffect | Before DOM mutations | CSS-in-JS style tag injection; prevents forced reflows |
useLayoutEffect | After DOM mutations, before browser paint | Measuring DOM nodes (getBoundingClientRect), preventing layout flickers |
useEffect | After browser paint | Network requests, event subscriptions, timers (99% of use cases) |
Preventing Layout Flicker with useLayoutEffect
Imagine positioning a Tooltip:
- Tooltip mounts at default
top: 0, left: 0. - If you use
useEffect: Browser paints tooltip at top-left. ThenuseEffectmeasures the anchor button, calculates real coordinates, updates state, and moves tooltip. The user sees a jarring visual flicker! - If you use
useLayoutEffect: It runs synchronously before the browser paints. It measures, sets coordinates, and the browser paints only the final correct position. Zero flicker!
Warning: Because useLayoutEffect is synchronous, heavy calculations inside it will freeze the browser main thread and delay paint.
Common Interview Traps & Pitfalls
Using useLayoutEffect for data fetching, delaying browser paint for network requests.
Using useInsertionEffect in general application code (it is exclusively for CSS-in-JS library authors).
Ignoring SSR warnings when useLayoutEffect runs on the server (it does nothing on the server).
Senior Interviewer Follow-Up Probes
Why does Next.js warn: "useLayoutEffect does nothing on the server"?
How does CSS-in-JS style injection in useLayoutEffect cause layout thrashing in Concurrent React?
How can you conditionally switch between useEffect on server and useLayoutEffect on client?
Frequently Asked Interview Questions
Why was useInsertionEffect introduced in React 18?
To solve CSS-in-JS performance issues. It injects <style> tags before any layout effects read DOM styles, preventing the browser from recalculating CSS rules multiple times during a single render pass.
Does useLayoutEffect run on the server in SSR?
No. useLayoutEffect does not execute during server-side rendering because there is no DOM to measure or mutate, triggering a React warning if not handled.
Can useLayoutEffect degrade application performance?
Yes. Because it runs synchronously, any slow computations or synchronous loops will block the browser from painting frames, making the UI feel sluggish.
How do you suppress the useLayoutEffect SSR warning in universal components?
By defining a custom hook: const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect.
