Skip to main content

📘 React useLayoutEffect — Complete In-Depth Guide


1. 🧠 Introduction

What is useLayoutEffect?

useLayoutEffect is a React Hook that runs synchronously after DOM mutations but before the browser paints.
useLayoutEffect(() => {
  // Runs before paint
}, []);
👉 It is similar to useEffect, but with a critical difference:
  • useEffect → runs after paint (async)
  • useLayoutEffect → runs before paint (sync)

Why it is Important in React

React normally:
  1. Updates DOM
  2. Lets browser paint
  3. Then runs effects (useEffect)
But sometimes, you need to:
  • Measure DOM size/position
  • Make visual adjustments before user sees anything
  • Avoid flickering/jumps
👉 That’s where useLayoutEffect becomes essential.

When and Why We Use It

Use useLayoutEffect when:

✅ You need to read layout

  • Element width/height
  • Scroll position
  • Bounding boxes

✅ You need to mutate DOM before paint

  • Adjust styles
  • Reposition elements

✅ You want to prevent visual flicker


❌ When NOT to use it

Avoid it when:
  • You are doing data fetching
  • You are running non-UI logic
  • You don’t depend on layout
👉 Because it blocks painting, overuse harms performance.

2. ⚙️ Concepts / Internal Workings


React Rendering Phases (Critical to Understand)

React works in two main phases:

1. Render Phase (Virtual DOM)

  • Pure calculation
  • No DOM mutations

2. Commit Phase (DOM updates)

Inside commit phase:
1. DOM updates applied
2. useLayoutEffect runs (SYNC)
3. Browser paints UI
4. useEffect runs (ASYNC)

How useLayoutEffect Works Internally

  • React finishes DOM updates
  • Before browser paints:
    • Runs all useLayoutEffect callbacks
  • Blocks paint until:
    • All layout effects complete
👉 This guarantees:
User never sees intermediate DOM states

Visual Timeline

Render → DOM Update → useLayoutEffect → Paint → useEffect

Relationship with Other Hooks

🔹 vs useEffect

FeatureuseLayoutEffectuseEffect
TimingBefore paintAfter paint
ExecutionSynchronousAsynchronous
PerformanceCan block UINon-blocking
Use caseLayout & measurementSide effects

🔹 vs useRef

  • useLayoutEffect + useRef is a common combo
  • Used for DOM access before paint
const ref = useRef();

useLayoutEffect(() => {
  console.log(ref.current.getBoundingClientRect());
}, []);

🔹 vs useEffect Cleanup

Cleanup timing:
  • useLayoutEffect cleanup → runs before next layout effect / before DOM changes
  • useEffect cleanup → runs later

Strict Mode Behavior (React 18+)

In development:
  • useLayoutEffect runs twice (mount + cleanup + mount)
👉 This helps detect:
  • Side effects
  • Unsafe mutations

3. 💻 Syntax & Examples


Basic Syntax

useLayoutEffect(() => {
  // logic
  return () => {
    // cleanup
  };
}, [dependencies]);

Example 1: Measuring DOM Size

import { useRef, useLayoutEffect, useState } from "react";

function Box() {
  const ref = useRef();
  const [width, setWidth] = useState(0);

  useLayoutEffect(() => {
    const rect = ref.current.getBoundingClientRect();
    setWidth(rect.width);
  }, []);

  return <div ref={ref}>Width: {width}</div>;
}
👉 Ensures width is calculated before paint, avoiding flicker.

Example 2: Prevent Layout Shift (Tooltip Positioning)

function Tooltip({ targetRef }) {
  const tooltipRef = useRef();
  const [position, setPosition] = useState({ top: 0, left: 0 });

  useLayoutEffect(() => {
    const targetRect = targetRef.current.getBoundingClientRect();
    setPosition({
      top: targetRect.bottom + 8,
      left: targetRect.left,
    });
  }, [targetRef]);

  return (
    <div ref={tooltipRef} style={{ position: "absolute", ...position }}>
      Tooltip
    </div>
  );
}
👉 Prevents the tooltip from jumping after render.

Example 3: Scroll Position Control

function Chat({ messages }) {
  const containerRef = useRef();

  useLayoutEffect(() => {
    containerRef.current.scrollTop =
      containerRef.current.scrollHeight;
  }, [messages]);

  return (
    <div ref={containerRef} style={{ height: 200, overflow: "auto" }}>
      {messages.map(m => <div key={m.id}>{m.text}</div>)}
    </div>
  );
}
👉 Ensures scroll happens before paint, avoiding visible jump.

Example 4: DOM Mutation Before Paint

useLayoutEffect(() => {
  document.body.style.backgroundColor = "black";

  return () => {
    document.body.style.backgroundColor = "white";
  };
}, []);

Mini Example: Difference Demo

useEffect(() => {
  console.log("useEffect");
});

useLayoutEffect(() => {
  console.log("useLayoutEffect");
});
👉 Output order:
useLayoutEffect
useEffect

4. ⚠️ Edge Cases / Common Mistakes


❗ 1. Overusing useLayoutEffect

Problem:

  • Blocks rendering
  • Causes performance lag

Fix:

👉 Default to useEffect unless layout is required

❗ 2. Causing Forced Reflows

useLayoutEffect(() => {
  const width = el.offsetWidth;
  el.style.width = width + 10 + "px";
});
👉 This can trigger:
  • Layout recalculation
  • Performance bottlenecks

❗ 3. Infinite Loops

useLayoutEffect(() => {
  setState(someValue);
}, [state]);
👉 Causes:
  • Re-render → layout effect → setState → loop

❗ 4. SSR Warning (Important)

useLayoutEffect does nothing on server React warns:
“useLayoutEffect does nothing on the server”

Fix:

const useIsomorphicLayoutEffect =
  typeof window !== "undefined" ? useLayoutEffect : useEffect;

❗ 5. Visual Flicker Misuse

Using useEffect instead:
useEffect(() => {
  // measure DOM
});
👉 Causes:
  • Flicker
  • Layout shift
👉 Should use useLayoutEffect

❗ 6. Heavy Computation Inside

useLayoutEffect(() => {
  expensiveCalculation(); // ❌ bad
});
👉 Blocks UI thread

5. ✅ Best Practices


✔️ 1. Prefer useEffect by Default

Only use useLayoutEffect when:
  • You must block paint

✔️ 2. Keep It Lightweight

useLayoutEffect(() => {
  // Only minimal DOM reads/writes
});
👉 Avoid:
  • API calls
  • heavy loops

✔️ 3. Batch DOM Reads & Writes

Bad:
const height = el.offsetHeight;
el.style.height = height + 10 + "px";
Better:
  • Read first
  • Then write

✔️ 4. Use with useRef (Best Pairing)

const ref = useRef();

useLayoutEffect(() => {
  ref.current.focus();
}, []);

✔️ 5. Avoid State Updates If Possible

Prefer direct DOM updates when safe:
ref.current.style.transform = "translateX(10px)";

✔️ 6. Handle SSR Properly

Create abstraction:
const useSafeLayoutEffect =
  typeof window !== "undefined"
    ? useLayoutEffect
    : useEffect;

✔️ 7. Measure Once, Cache Smartly

Avoid repeated layout reads:
  • Use refs
  • Memoize values

✔️ 8. Combine with requestAnimationFrame (Advanced)

useLayoutEffect(() => {
  requestAnimationFrame(() => {
    // smoother updates
  });
}, []);

🧾 Final Mental Model

👉 Think of useLayoutEffect as:
“A hook for reading and fixing layout before the user sees anything.”

🔑 Golden Rule

  • 90% of cases → useEffect
  • 10% → useLayoutEffect (only for layout-critical work)

Below is a senior-level, depth-focused interview set on useLayoutEffect. Each question is designed to probe mental models, trade-offs, and real-world decision-making, not just API recall.

🧠 Advanced useLayoutEffect Interview Questions (with Answers)


1. What problem does useLayoutEffect solve that useEffect cannot?

✅ Strong Answer

The core problem is visual consistency before paint.
  • useEffect runs after the browser paints, so any DOM reads/writes can cause:
    • Flicker
    • Layout shifts (CLS issues)
  • useLayoutEffect runs before paint, allowing:
    • Synchronous DOM reads
    • Immediate DOM corrections
👉 This guarantees:
The user only sees the final, corrected layout.

Example

useEffect(() => {
  setPosition(calculatePosition());
});
❌ Causes flicker
useLayoutEffect(() => {
  setPosition(calculatePosition());
});
✅ No flicker

💡 Why this matters

Because render ≠ visually stable UI. Layout effects ensure visual correctness before display.

2. Walk through the exact execution order of useLayoutEffect in React’s lifecycle.

✅ Strong Answer

React commit phase order:
1. Render phase (pure, no DOM)
2. DOM mutations applied
3. useLayoutEffect runs (SYNC, blocks paint)
4. Browser paints
5. useEffect runs (ASYNC)

Key Insight

  • useLayoutEffect is part of the commit phase
  • It runs after DOM is updated but before paint

Why this design?

React separates:
  • Mutation phase → apply DOM
  • Layout phase → measure/fix layout
  • Passive phase → async side effects

3. Why is useLayoutEffect considered dangerous for performance?

✅ Strong Answer

Because it blocks the browser’s paint cycle.
  • Runs synchronously
  • Prevents UI from updating until it completes

Impact

  • Long tasks → UI freezes
  • Multiple layout effects → cumulative delay

Example

useLayoutEffect(() => {
  heavyComputation(); // blocks paint ❌
});

Better

useEffect(() => {
  heavyComputation(); // non-blocking ✅
});

💡 Trade-off

BenefitCost
No flickerBlocks rendering
Accurate layoutSlower perceived UI

4. How does useLayoutEffect interact with the browser’s rendering pipeline?

✅ Strong Answer

Browser pipeline:
JS → Style → Layout → Paint → Composite
React inserts itself:
DOM update → useLayoutEffect → Paint

Key Point

  • It runs after layout calculation but before paint
  • Any DOM reads (e.g., getBoundingClientRect) are accurate

Risk

If you:
  • Read → write → read again 👉 You trigger forced synchronous reflow

5. Explain forced reflow and how useLayoutEffect can cause it.

✅ Strong Answer

Forced reflow happens when:
  • Browser must recalculate layout immediately

Example

useLayoutEffect(() => {
  const width = el.offsetWidth; // read
  el.style.width = width + 10 + "px"; // write
  const newWidth = el.offsetWidth; // read again → forced reflow ❌
});

Why dangerous?

  • Breaks browser optimizations
  • Causes layout thrashing

Fix

👉 Batch reads and writes:
useLayoutEffect(() => {
  const width = el.offsetWidth;
  el.style.width = width + 10 + "px";
});

6. Why does React warn about useLayoutEffect on the server?

✅ Strong Answer

Because:
  • There is no DOM on the server
  • No layout or paint phase exists
So:
useLayoutEffect cannot run meaningfully

Warning

“useLayoutEffect does nothing on the server”

Solution

const useIsomorphicLayoutEffect =
  typeof window !== "undefined"
    ? useLayoutEffect
    : useEffect;

Why important?

Prevents:
  • Hydration mismatches
  • Console warnings

7. How does useLayoutEffect behave in React Strict Mode?

✅ Strong Answer

In development:
  • React runs:
    • setup → cleanup → setup

Why?

To detect:
  • Side effects
  • Non-idempotent logic

Example

useLayoutEffect(() => {
  console.log("run");
  return () => console.log("cleanup");
}, []);
Output (dev):
run
cleanup
run

Implication

Your effect must be:
  • Pure
  • Repeatable

8. When would you choose useLayoutEffect over CSS solutions?

✅ Strong Answer

Prefer CSS when possible. Use useLayoutEffect only when:
  • Layout depends on runtime measurements

Example

❌ Avoid JS:
useLayoutEffect(() => {
  el.style.height = window.innerHeight + "px";
});
✅ Prefer CSS:
height: 100vh;

When JS is needed:

  • Dynamic tooltip positioning
  • Canvas measurements
  • Virtualized lists

9. How would you implement a flicker-free tooltip system?

✅ Strong Answer

Key requirement:
  • Measure target
  • Position tooltip
  • Do it before paint

Solution

useLayoutEffect(() => {
  const rect = targetRef.current.getBoundingClientRect();
  setPosition({
    top: rect.bottom,
    left: rect.left,
  });
}, []);

Why not useEffect?

Because:
  • Tooltip would render at wrong position first
  • Then jump → bad UX

10. What are the trade-offs between useLayoutEffect and requestAnimationFrame?

✅ Strong Answer

AspectuseLayoutEffectrequestAnimationFrame
TimingBefore paintBefore next frame
BlockingYesNo
Use caseCritical layout fixesSmooth animations

Combined usage

useLayoutEffect(() => {
  requestAnimationFrame(() => {
    animate();
  });
});

Insight

  • useLayoutEffect = correctness
  • rAF = smoothness

11. Can useLayoutEffect cause infinite render loops? How?

✅ Strong Answer

Yes, if state updates are not controlled.
useLayoutEffect(() => {
  setState(value); // triggers re-render
}, [state]);
👉 Loop:
  • render → layout effect → setState → render → …

Fix

  • Use correct dependencies
  • Guard updates
useLayoutEffect(() => {
  if (state !== value) {
    setState(value);
  }
}, [value]);

12. Why is useLayoutEffect commonly paired with useRef?

✅ Strong Answer

Because:
  • useRef gives direct DOM access
  • useLayoutEffect guarantees DOM is ready

Pattern

const ref = useRef();

useLayoutEffect(() => {
  ref.current.focus();
}, []);

Why not during render?

Because:
  • DOM doesn’t exist yet

13. How does useLayoutEffect behave with concurrent rendering?

✅ Strong Answer

Important nuance:
  • Concurrent rendering affects render phase
  • useLayoutEffect runs only in commit phase
👉 So:
  • It is always synchronous
  • Cannot be interrupted

Implication

  • Still blocks paint
  • Not “concurrent-friendly”

14. What happens if multiple useLayoutEffect hooks exist?

✅ Strong Answer

They run:
  • In order of declaration
  • All before paint

Example

useLayoutEffect(() => console.log(1));
useLayoutEffect(() => console.log(2));
Output:
1
2

Insight

  • Order matters for DOM dependencies

15. How would you debug a layout shift issue in React?

✅ Strong Answer

Steps:
  1. Identify flicker/jump
  2. Check:
    • Is measurement happening in useEffect?
  3. Move to useLayoutEffect

Tools

  • Chrome DevTools → Performance tab
  • Layout shift visualization

Root Cause

  • DOM updated after paint

16. Why is useLayoutEffect not suitable for data fetching?

✅ Strong Answer

Because:
  • It blocks paint
  • Fetching is async and non-visual

Bad

useLayoutEffect(() => {
  fetchData();
});

Good

useEffect(() => {
  fetchData();
});

Principle

👉 Layout effects = visual correctness only

17. How would you design a custom hook that safely uses useLayoutEffect?

✅ Strong Answer

Abstract SSR + layout logic:
const useSafeLayoutEffect =
  typeof window !== "undefined"
    ? useLayoutEffect
    : useEffect;

function useMeasure(ref) {
  const [rect, setRect] = useState(null);

  useSafeLayoutEffect(() => {
    setRect(ref.current.getBoundingClientRect());
  }, []);

  return rect;
}

Benefits

  • SSR-safe
  • Reusable
  • Encapsulates complexity

18. What mental model should developers use for useLayoutEffect?

✅ Strong Answer

Think of it as:
“A synchronous hook to read and fix layout before the user sees anything.”

Decision heuristic

Ask:
  1. Does this affect visual layout immediately?
  2. Will the user see a wrong state before correction?
If YES → useLayoutEffect Else → useEffect

🔥 Final Insight

Senior engineers don’t just know how useLayoutEffect works — they know:
  • When NOT to use it
  • How it impacts rendering performance
  • How it interacts with the browser pipeline

Below is a senior-level MCQ set on useLayoutEffect designed to test deep mental models, edge cases, and real-world reasoning.

🧠 Advanced MCQs — useLayoutEffect


1. You observe a flicker when positioning a dropdown after render. What is the most correct fix?

useEffect(() => {
  const rect = ref.current.getBoundingClientRect();
  setPosition(rect);
}, []);

Options:

A. Wrap in requestAnimationFrame B. Replace with useLayoutEffect C. Move logic inside render D. Use setTimeout

✅ Correct Answer: B

Explanation:

  • The flicker occurs because:
    • useEffect runs after paint
    • Initial incorrect UI is visible
👉 useLayoutEffect runs before paint, preventing flicker.

Why others are wrong:

  • A: requestAnimationFrame still runs after paint → flicker remains
  • C: DOM is not available during render
  • D: Makes timing worse (even later)

2. What is the primary performance risk of using useLayoutEffect excessively?

Options:

A. Memory leaks B. Blocking browser paint C. Delayed network requests D. Increased bundle size

✅ Correct Answer: B

Explanation:

  • useLayoutEffect is synchronous and blocks paint
  • Long operations → visible UI lag

Why others are wrong:

  • A: Possible, but not primary risk
  • C: Not related
  • D: Hook usage doesn’t affect bundle size

3. In what order do these logs execute?

useEffect(() => console.log("effect"));
useLayoutEffect(() => console.log("layout"));
console.log("render");

Options:

A. render → effect → layout B. render → layout → effect C. layout → render → effect D. render → effect → layout

✅ Correct Answer: B

Explanation:

Execution order:
render → useLayoutEffect → useEffect

Why others are wrong:

  • A/D: Incorrect ordering of layout/effect
  • C: Layout cannot run before render

4. What happens if useLayoutEffect triggers a state update on every render?

Options:

A. React ignores it B. It runs once C. Infinite render loop D. React batches updates and stops loop

✅ Correct Answer: C

Explanation:

  • setState inside layout effect:
    • Causes re-render
    • Effect runs again → loop

Why others are wrong:

  • A: React does not ignore
  • B: Not true without dependency control
  • D: Batching doesn’t prevent loops

5. Why does React warn about useLayoutEffect in SSR?

Options:

A. It causes hydration failure B. It blocks rendering on server C. No DOM/layout exists on server D. It runs twice on server

✅ Correct Answer: C

Explanation:

  • Server has:
    • No DOM
    • No layout/paint
👉 Hook has no meaning

Why others are wrong:

  • A: Not inherently true
  • B: Server rendering is synchronous anyway
  • D: Incorrect

6. Which scenario justifies using useLayoutEffect over CSS?

Options:

A. Setting static height B. Dynamic measurement-based positioning C. Styling hover states D. Applying theme colors

✅ Correct Answer: B

Explanation:

  • CSS cannot handle:
    • Runtime measurements
    • Dynamic positioning logic

Why others are wrong:

  • A/C/D: Better handled with CSS

7. What is a forced reflow?

Options:

A. React re-render cycle B. Browser recalculating layout synchronously C. DOM repaint D. State update batching

✅ Correct Answer: B

Explanation:

  • Happens when:
    • Layout is recalculated immediately
  • Often triggered by:
    • Read → write → read pattern

Why others are wrong:

  • A/D: React concepts
  • C: Paint ≠ layout recalculation

8. Which code is most likely to cause layout thrashing?

Options:

A.
const w = el.offsetWidth;
el.style.width = w + "px";
B.
const w = el.offsetWidth;
const h = el.offsetHeight;
C.
el.style.width = "100px";
D.
const w1 = el.offsetWidth;
el.style.width = w1 + "px";
const w2 = el.offsetWidth;

✅ Correct Answer: D

Explanation:

  • Pattern:
    • Read → Write → Read 👉 Forces reflow

Why others are wrong:

  • A: Single read/write
  • B: Only reads
  • C: Only write

9. In Strict Mode, what happens to useLayoutEffect?

Options:

A. Runs once B. Runs twice (mount + cleanup + mount) C. Skipped entirely D. Runs asynchronously

✅ Correct Answer: B

Explanation:

  • Dev-only behavior:
    • Detect side effects

Why others are wrong:

  • A: Not in Strict Mode
  • C/D: Incorrect behavior

10. Which is the best use case for useLayoutEffect?

Options:

A. Fetching API data B. Logging analytics C. Measuring DOM before positioning D. Updating global state

✅ Correct Answer: C

Explanation:

  • Layout measurement requires:
    • DOM + sync execution before paint

Why others are wrong:

  • A/B/D: Non-layout side effects → useEffect

11. What happens if useLayoutEffect contains heavy computation?

Options:

A. It runs in background B. UI becomes unresponsive C. React skips it D. It moves to useEffect automatically

✅ Correct Answer: B

Explanation:

  • Blocks paint → freezes UI

Why others are wrong:

  • A: Not async
  • C/D: React does not optimize this

12. Which pairing is most common with useLayoutEffect?

Options:

A. useState B. useReducer C. useRef D. useMemo

✅ Correct Answer: C

Explanation:

  • useRef provides DOM access
  • Required for layout measurements

13. Why shouldn’t you use useLayoutEffect for data fetching?

Options:

A. It doesn’t support async B. It blocks paint unnecessarily C. It causes memory leaks D. It fails in production

✅ Correct Answer: B

Explanation:

  • Fetching is:
    • Non-visual
    • Async
👉 Blocking paint is wasteful

14. What guarantees does useLayoutEffect provide?

Options:

A. Runs after paint B. Runs before DOM updates C. Runs after DOM updates but before paint D. Runs during render

✅ Correct Answer: C

Explanation:

  • Key guarantee:
    • DOM is updated
    • UI not yet visible

15. How are multiple useLayoutEffect hooks executed?

Options:

A. Random order B. Parallel C. In declaration order D. Based on dependencies

✅ Correct Answer: C

Explanation:

  • Deterministic order
  • Important for DOM dependencies

16. Which approach avoids SSR warnings?

Options:

A.
useLayoutEffect(...)
B.
useEffect(...)
C.
const useSafe = typeof window !== "undefined"
  ? useLayoutEffect
  : useEffect;
D. Disable SSR

✅ Correct Answer: C

Explanation:

  • Safely switches behavior based on environment

17. Why might requestAnimationFrame be combined with useLayoutEffect?

Options:

A. To delay rendering B. To move work after paint C. To smooth animations after layout correction D. To avoid dependency arrays

✅ Correct Answer: C

Explanation:

  • Pattern:
    • Layout fix → rAF → animation

18. What is the biggest conceptual difference between useEffect and useLayoutEffect?

Options:

A. Dependency handling B. Execution timing relative to paint C. Cleanup behavior D. Hook syntax

✅ Correct Answer: B

Explanation:

  • Everything else is same
  • Timing is the core difference

🔥 Final Takeaway

These questions target whether a candidate understands:
  • Rendering pipeline
  • Browser internals
  • Performance implications
  • When NOT to use useLayoutEffect

Below is a senior-level coding problem set for useLayoutEffect, designed around real-world UI systems, layout correctness, and performance trade-offs.

🧠 Advanced Coding Problems — useLayoutEffect


1. Flicker-Free Tooltip Engine

🧩 Problem

Build a tooltip component that:
  • Appears below a target element
  • Repositions based on viewport constraints
  • Never flickers or jumps

Constraints

  • Must avoid layout shift
  • Tooltip should flip (top/bottom) if space is insufficient
  • No external libraries

Expected Behavior

  • Tooltip appears in correct position immediately
  • No visible repositioning

Edge Cases

  • Near viewport edges
  • Dynamic content size
  • Window resize

✅ Solution Approach

  1. Use useRef for DOM nodes
  2. Use useLayoutEffect to:
    • Measure target + tooltip
    • Compute position
  3. Update state before paint
useLayoutEffect(() => {
  const targetRect = targetRef.current.getBoundingClientRect();
  const tooltipRect = tooltipRef.current.getBoundingClientRect();

  let top = targetRect.bottom;
  if (top + tooltipRect.height > window.innerHeight) {
    top = targetRect.top - tooltipRect.height;
  }

  setPosition({ top, left: targetRect.left });
}, []);

💡 Why useLayoutEffect?

Prevents visible repositioning flicker.

2. Virtualized List with Dynamic Row Heights

🧩 Problem

Render a large list where:
  • Each row has unknown height
  • Only visible rows are rendered

Constraints

  • Must measure row height dynamically
  • Smooth scrolling
  • No layout jumps

Expected Behavior

  • Accurate scroll position
  • No flickering rows

Edge Cases

  • Rapid scroll
  • Dynamic content updates

✅ Solution Approach

  • Use useLayoutEffect to measure row height after render
  • Store heights in a map
  • Adjust scroll offsets
useLayoutEffect(() => {
  const height = ref.current.offsetHeight;
  heightMap.set(index, height);
}, [content]);

💡 Insight

Using useEffect would cause incorrect scroll calculations initially.

3. Sticky Header Without Layout Shift

🧩 Problem

Create a header that:
  • Becomes sticky after scrolling
  • Does not cause content jump

Constraints

  • Must maintain layout consistency

Expected Behavior

  • Smooth transition
  • No sudden shift

Edge Cases

  • Resize
  • Dynamic header height

✅ Solution

  • Measure header height using useLayoutEffect
  • Apply placeholder spacing
useLayoutEffect(() => {
  const height = headerRef.current.offsetHeight;
  setHeaderHeight(height);
}, []);

4. Auto-Scrolling Chat Window

🧩 Problem

Implement chat UI that:
  • Scrolls to latest message automatically
  • Does not show scroll jump

Constraints

  • Only scroll if user is at bottom

Expected Behavior

  • Smooth UX

Edge Cases

  • User scrolls up manually
  • Large message batches

✅ Solution

useLayoutEffect(() => {
  if (isAtBottom) {
    containerRef.current.scrollTop =
      containerRef.current.scrollHeight;
  }
}, [messages]);

5. Resizable Panel System

🧩 Problem

Create draggable panels:
  • Width updates in real-time
  • Layout stays stable

Constraints

  • No flicker
  • High performance

Edge Cases

  • Rapid drag
  • Window resize

✅ Solution

  • Track drag position
  • Use useLayoutEffect to sync DOM updates
useLayoutEffect(() => {
  panelRef.current.style.width = width + "px";
}, [width]);

6. Prevent Layout Shift on Image Load

🧩 Problem

Images load asynchronously causing layout shifts.

Constraints

  • Maintain placeholder size

Expected Behavior

  • No CLS (Cumulative Layout Shift)

✅ Solution

useLayoutEffect(() => {
  const { width, height } = imgRef.current;
  setDimensions({ width, height });
}, []);

7. Dynamic Grid Masonry Layout

🧩 Problem

Build Pinterest-style grid:
  • Items have variable heights
  • Layout must be compact

✅ Solution

  • Measure each item
  • Calculate column placement in useLayoutEffect

8. Drag-and-Drop Ghost Element Positioning

🧩 Problem

While dragging:
  • Show ghost element following cursor
  • Must match original element size

✅ Solution

useLayoutEffect(() => {
  const rect = ref.current.getBoundingClientRect();
  setGhostStyle({ width: rect.width, height: rect.height });
}, []);

9. Scroll Restoration System

🧩 Problem

Restore scroll position when navigating back.

✅ Solution

useLayoutEffect(() => {
  window.scrollTo(0, savedScrollY);
}, []);

10. Adaptive Dropdown Width Matching Trigger

🧩 Problem

Dropdown width should match trigger width.

✅ Solution

useLayoutEffect(() => {
  const width = triggerRef.current.offsetWidth;
  setDropdownWidth(width);
}, []);

11. Focus Trap Modal

🧩 Problem

Ensure focus stays inside modal.

✅ Solution

useLayoutEffect(() => {
  firstFocusable.current.focus();
}, []);

12. Measure Before Animation Starts

🧩 Problem

Animate element from initial position.

✅ Solution

useLayoutEffect(() => {
  const rect = ref.current.getBoundingClientRect();
  setInitialRect(rect);
}, []);

13. Prevent Scroll Jump on Content Expansion

🧩 Problem

Expanding content shifts scroll unexpectedly.

✅ Solution

  • Capture scroll position
  • Restore after update
useLayoutEffect(() => {
  const prev = window.scrollY;
  // update DOM
  window.scrollTo(0, prev);
});

14. Multi-Step Form Progress Indicator Alignment

🧩 Problem

Align progress bar with steps dynamically.

✅ Solution

  • Measure step positions using useLayoutEffect

15. Detect Element Overflow

🧩 Problem

Show “Read more” if content overflows.

✅ Solution

useLayoutEffect(() => {
  const isOverflowing =
    el.scrollHeight > el.clientHeight;
  setOverflow(isOverflowing);
}, []);

16. Dynamic Canvas Drawing Based on Size

🧩 Problem

Canvas must adapt to container size.

✅ Solution

useLayoutEffect(() => {
  const rect = containerRef.current.getBoundingClientRect();
  canvas.width = rect.width;
  canvas.height = rect.height;
}, []);

17. Sticky Sidebar with Dynamic Height

🧩 Problem

Sidebar should not overflow viewport.

✅ Solution

  • Measure height and adjust maxHeight dynamically

18. Keyboard Navigation with Scroll Into View

🧩 Problem

Focused item should scroll into view.

✅ Solution

useLayoutEffect(() => {
  activeRef.current.scrollIntoView({ block: "nearest" });
}, [activeIndex]);

19. Collapsible Sections with Height Animation

🧩 Problem

Animate height from 0 → auto.

✅ Solution

  • Measure full height first using useLayoutEffect
  • Then animate

🔥 Final Takeaways

These problems test whether you can:
  • Control layout before paint
  • Prevent flicker & layout shifts
  • Handle DOM measurement correctly
  • Balance performance vs correctness

Below are senior-level debugging challenges around useLayoutEffect, modeled after real production bugs—subtle, non-obvious, and rooted in React lifecycle + browser behavior.

🧠 Debugging Challenges — useLayoutEffect


1. Infinite Render Loop via Measurement

🐛 Buggy Code

function Box() {
  const ref = useRef();
  const [width, setWidth] = useState(0);

  useLayoutEffect(() => {
    const w = ref.current.offsetWidth;
    setWidth(w);
  }, [width]);

  return <div ref={ref}>{width}</div>;
}

❌ What’s Wrong

  • Effect depends on width
  • Effect updates width → triggers re-render → loop

🤯 Why It Happens

  • useLayoutEffect runs after every render where dependency changes
  • State update inside effect creates circular dependency

✅ Fixed Code

useLayoutEffect(() => {
  const w = ref.current.offsetWidth;
  setWidth(w);
}, []); // run once

💡 Best Practice

👉 Avoid putting derived state from DOM in dependency arrays 👉 Use guards if needed

2. Flicker Despite Using useLayoutEffect

🐛 Buggy Code

useLayoutEffect(() => {
  setPosition(getPosition());
}, []);

❌ What’s Wrong

  • Initial render still uses default position
  • State update triggers second render

🤯 Why It Happens

  • First render happens before effect runs
  • Even though it’s before paint, layout recalculation still causes shift

✅ Fix

const position = getPosition(); // compute during render
OR
const [position, setPosition] = useState(null);

useLayoutEffect(() => {
  setPosition(getPosition());
}, []);

if (!position) return null;

💡 Best Practice

👉 Avoid rendering incomplete layout → delay render if needed

3. Layout Thrashing from Mixed Reads/Writes

🐛 Buggy Code

useLayoutEffect(() => {
  const height = el.offsetHeight;
  el.style.height = height + 20 + "px";
  const newHeight = el.offsetHeight;
});

❌ What’s Wrong

  • Read → Write → Read pattern

🤯 Why It Happens

  • Browser forced to recalculate layout twice → expensive

✅ Fix

useLayoutEffect(() => {
  const height = el.offsetHeight;
  el.style.height = height + 20 + "px";
});

💡 Best Practice

👉 Batch reads first, then writes

4. SSR Warning in Production Logs

🐛 Buggy Code

useLayoutEffect(() => {
  document.title = "Hello";
}, []);

❌ What’s Wrong

  • useLayoutEffect used in SSR environment

🤯 Why It Happens

  • No DOM on server → React warns

✅ Fix

const useSafeLayoutEffect =
  typeof window !== "undefined" ? useLayoutEffect : useEffect;

useSafeLayoutEffect(() => {
  document.title = "Hello";
}, []);

💡 Best Practice

👉 Always handle SSR when using layout effects

5. Janky Drag Performance

🐛 Buggy Code

useLayoutEffect(() => {
  element.style.left = x + "px";
}, [x]);

❌ What’s Wrong

  • Runs on every drag update synchronously

🤯 Why It Happens

  • Blocks paint during rapid updates → lag

✅ Fix

useEffect(() => {
  requestAnimationFrame(() => {
    element.style.left = x + "px";
  });
}, [x]);

💡 Best Practice

👉 Use useLayoutEffect only for critical layout corrections, not continuous updates

6. Stale DOM Reference

🐛 Buggy Code

useLayoutEffect(() => {
  console.log(ref.current.offsetHeight);
}, []);

❌ What’s Wrong

  • Ref might not be updated if conditional rendering

🤯 Why It Happens

  • Effect runs before ref is set in some cases

✅ Fix

useLayoutEffect(() => {
  if (ref.current) {
    console.log(ref.current.offsetHeight);
  }
});

💡 Best Practice

👉 Always null-check refs

7. Scroll Jump on Content Update

🐛 Buggy Code

useLayoutEffect(() => {
  window.scrollTo(0, document.body.scrollHeight);
}, [items]);

❌ What’s Wrong

  • Forces scroll even if user scrolled up

🤯 Why It Happens

  • No user intent check

✅ Fix

useLayoutEffect(() => {
  const isAtBottom =
    window.innerHeight + window.scrollY >= document.body.scrollHeight;

  if (isAtBottom) {
    window.scrollTo(0, document.body.scrollHeight);
  }
}, [items]);

💡 Best Practice

👉 Respect user scroll behavior

8. Double Execution in Strict Mode Breaks Logic

🐛 Buggy Code

useLayoutEffect(() => {
  initializeLibrary();
}, []);

❌ What’s Wrong

  • Library initializes twice in dev

🤯 Why It Happens

  • Strict Mode double-invokes effects

✅ Fix

const initialized = useRef(false);

useLayoutEffect(() => {
  if (!initialized.current) {
    initializeLibrary();
    initialized.current = true;
  }
}, []);

💡 Best Practice

👉 Make effects idempotent

9. Incorrect Dependency Causing Missed Updates

🐛 Buggy Code

useLayoutEffect(() => {
  updatePosition(targetRef.current);
}, []);

❌ What’s Wrong

  • Doesn’t update when target changes

🤯 Why It Happens

  • Missing dependency

✅ Fix

useLayoutEffect(() => {
  updatePosition(targetRef.current);
}, [targetRef]);

💡 Best Practice

👉 Treat layout effects like pure functions of dependencies

10. Measuring Before DOM Update Completes

🐛 Buggy Code

setItems(newItems);

useLayoutEffect(() => {
  measure();
}, []);

❌ What’s Wrong

  • Effect doesn’t depend on items

🤯 Why It Happens

  • Effect runs before new DOM is reflected

✅ Fix

useLayoutEffect(() => {
  measure();
}, [items]);

💡 Best Practice

👉 Always sync effect with DOM-changing state

11. Hidden Performance Bottleneck

🐛 Buggy Code

useLayoutEffect(() => {
  expensiveCalculation();
}, []);

❌ What’s Wrong

  • Heavy computation blocks paint

🤯 Why It Happens

  • Synchronous execution

✅ Fix

useEffect(() => {
  expensiveCalculation();
}, []);

💡 Best Practice

👉 Keep layout effects minimal

12. Tooltip Misalignment on Resize

🐛 Buggy Code

useLayoutEffect(() => {
  positionTooltip();
}, []);

❌ What’s Wrong

  • Doesn’t update on resize

🤯 Why It Happens

  • Effect only runs once

✅ Fix

useLayoutEffect(() => {
  positionTooltip();
  window.addEventListener("resize", positionTooltip);
  return () => window.removeEventListener("resize", positionTooltip);
}, []);

💡 Best Practice

👉 Handle environmental changes (resize, scroll)

13. Memory Leak via Event Listener

🐛 Buggy Code

useLayoutEffect(() => {
  window.addEventListener("scroll", handleScroll);
}, []);

❌ What’s Wrong

  • No cleanup

🤯 Why It Happens

  • Listener persists after unmount

✅ Fix

useLayoutEffect(() => {
  window.addEventListener("scroll", handleScroll);
  return () => window.removeEventListener("scroll", handleScroll);
}, []);

💡 Best Practice

👉 Always clean up side effects

14. Race Condition with State Updates

🐛 Buggy Code

useLayoutEffect(() => {
  setWidth(ref.current.offsetWidth);
  setHeight(ref.current.offsetHeight);
}, []);

❌ What’s Wrong

  • Multiple state updates → multiple renders

🤯 Why It Happens

  • Each setState triggers render

✅ Fix

useLayoutEffect(() => {
  const rect = ref.current.getBoundingClientRect();
  setSize({ width: rect.width, height: rect.height });
}, []);

💡 Best Practice

👉 Batch related state updates

15. Animation Starts from Wrong Position

🐛 Buggy Code

useEffect(() => {
  startAnimation();
}, []);

❌ What’s Wrong

  • Animation starts after paint

🤯 Why It Happens

  • Initial frame rendered incorrectly

✅ Fix

useLayoutEffect(() => {
  startAnimation();
}, []);

💡 Best Practice

👉 Use layout effect for initial animation setup

🔥 Final Insight

These bugs test whether you understand:
  • React commit phase deeply
  • Browser rendering pipeline
  • Performance trade-offs
  • Real-world UI behavior

Below is a production-grade machine coding set focused on useLayoutEffect. These are the kinds of problems that test architecture, rendering correctness, performance, and real-world trade-offs—not just implementation.

🧠 Real-World Machine Coding Problems — useLayoutEffect


1. Smart Tooltip System (Flip + Collision Detection)

📌 Requirements

  • Tooltip appears on hover
  • Positions relative to target
  • Flips (top/bottom/left/right) if space is insufficient
  • Supports dynamic content

🎯 UI Behavior

  • No flicker or jump
  • Smooth appearance
  • Accurate placement

🔄 State / Data Flow

  • targetRect
  • tooltipRect
  • placement

⚠️ Edge Cases

  • Near viewport edges
  • Scroll container offsets
  • Dynamic tooltip size

🚀 Performance Considerations

  • Avoid repeated measurements
  • Cache dimensions where possible

🏗 Suggested Architecture

  • TooltipProvider
  • useTooltipPosition hook
  • Portal rendering

🛠 Solution Approach

  1. Render tooltip offscreen initially
  2. Use useLayoutEffect:
    • Measure both elements
    • Compute optimal placement
  3. Update state before paint

2. Virtualized Infinite List (Dynamic Heights)

📌 Requirements

  • Render only visible items
  • Support variable row heights
  • Infinite scrolling

🎯 UI Behavior

  • Smooth scroll
  • No jump during measurement

🔄 State

  • scrollTop
  • visibleRange
  • itemHeights

⚠️ Edge Cases

  • Fast scrolling
  • Resize events
  • Data updates

🚀 Performance

  • Minimize reflows
  • Avoid full list recalculation

🏗 Architecture

  • Windowing engine
  • Height map cache
  • useLayoutEffect for measurement

🛠 Approach

  • Render estimated height
  • Measure real height in useLayoutEffect
  • Adjust offsets

3. Drag-and-Drop Builder (Like Notion / Figma Layers)

📌 Requirements

  • Drag elements vertically
  • Show placeholder position
  • Smooth reorder

🎯 Behavior

  • Ghost element follows cursor
  • Accurate drop preview

🔄 State

  • dragIndex
  • hoverIndex
  • positions

⚠️ Edge Cases

  • Rapid drag
  • Nested lists

🚀 Performance

  • Avoid blocking UI during drag

🏗 Architecture

  • Context for drag state
  • Layout measurement hook

🛠 Approach

  • Measure all item positions in useLayoutEffect
  • Calculate insertion index dynamically

4. Sticky Section Headers (Grouped List)

📌 Requirements

  • Sections stick to top while scrolling
  • Multiple groups

🎯 Behavior

  • Smooth transitions between sections

🔄 State

  • currentSection
  • sectionOffsets

⚠️ Edge Cases

  • Variable heights
  • Dynamic data

🚀 Performance

  • Avoid recalculating on every scroll

🏗 Architecture

  • Intersection observer + fallback measurement

🛠 Approach

  • Measure section offsets in useLayoutEffect
  • Track scroll position

5. Auto-Resizing Textarea (With Max Height + Scroll)

📌 Requirements

  • Textarea grows with content
  • Stops at max height → scrolls

🎯 Behavior

  • No flicker while resizing

⚠️ Edge Cases

  • Pasting large content
  • Deleting text

🛠 Approach

useLayoutEffect(() => {
  textarea.style.height = "auto";
  textarea.style.height = textarea.scrollHeight + "px";
}, [value]);

6. Modal with Focus Trap + Scroll Lock

📌 Requirements

  • Trap focus inside modal
  • Prevent background scroll

🎯 Behavior

  • No focus flicker

🛠 Approach

  • Focus first element in useLayoutEffect
  • Apply overflow: hidden to body

7. Dynamic Masonry Grid (Pinterest Layout)

📌 Requirements

  • Variable height cards
  • Balanced columns

🛠 Approach

  • Measure card heights in useLayoutEffect
  • Assign to shortest column

8. Scroll Sync Between Two Panels

📌 Requirements

  • Two panels scroll together

⚠️ Edge Cases

  • Prevent infinite loop sync

🛠 Approach

  • Use flag to prevent recursive updates
  • Sync scroll in useLayoutEffect

9. Responsive Navigation Overflow (More Menu)

📌 Requirements

  • Items overflow into “More” dropdown

🛠 Approach

  • Measure container + items width
  • Move overflow items dynamically

📌 Requirements

  • Maintain layout before images load

🛠 Approach

  • Measure container
  • Apply placeholder size using useLayoutEffect

11. Keyboard Navigation + Auto Scroll Into View

📌 Requirements

  • Arrow keys navigate list
  • Active item always visible

🛠 Approach

useLayoutEffect(() => {
  activeRef.current.scrollIntoView({ block: "nearest" });
}, [activeIndex]);

12. Animated Expand/Collapse (Height Auto Problem)

📌 Requirements

  • Animate height: 0 → auto

🛠 Approach

  1. Measure full height in useLayoutEffect
  2. Animate explicitly

13. Sticky Sidebar with Dynamic Constraints

📌 Requirements

  • Sidebar sticks but stops before footer

🛠 Approach

  • Measure container + footer positions
  • Adjust top dynamically

14. Canvas-Based Chart with Resize Awareness

📌 Requirements

  • Chart resizes with container

🛠 Approach

useLayoutEffect(() => {
  const rect = container.getBoundingClientRect();
  canvas.width = rect.width;
}, []);

15. Scroll Position Restoration (SPA Navigation)

📌 Requirements

  • Restore scroll on back navigation

🛠 Approach

useLayoutEffect(() => {
  window.scrollTo(0, savedPosition);
}, []);

16. Dynamic Form Step Indicator Alignment

📌 Requirements

  • Progress bar aligns with steps

🛠 Approach

  • Measure step positions
  • Update progress width

17. Overflow Detection with “Read More”

📌 Requirements

  • Detect if text is truncated

🛠 Approach

useLayoutEffect(() => {
  setOverflow(el.scrollHeight > el.clientHeight);
}, []);

18. Drag-to-Resize Table Columns

📌 Requirements

  • Resize columns via drag

⚠️ Edge Cases

  • Min/max width
  • Table overflow

🛠 Approach

  • Update widths via useLayoutEffect
  • Sync DOM immediately

📌 Requirements

  • FAB sticks bottom-right
  • Moves up when footer visible

🛠 Approach

  • Measure footer position
  • Adjust FAB offset

🔥 Final Architectural Insight

All these problems test one core idea:
Can you control layout before paint while balancing performance?

🧩 Senior-Level Thinking

When solving:
  • Ask:
    • “Will the user see an incorrect frame?”
  • Decide:
    • useEffect vs useLayoutEffect
  • Optimize:
    • Avoid blocking paint unnecessarily

Below is a senior-level interview set on useLayoutEffect designed to evaluate deep understanding, decision-making, and real-world debugging ability.

🧠 Advanced Interview Questions — useLayoutEffect


1. When would you intentionally choose useLayoutEffect over useEffect, knowing it can hurt performance?

🔍 Follow-up

  • What signals tell you this is necessary?
  • Can you redesign to avoid it?

✅ Strong Answer

Use useLayoutEffect when visual correctness must be guaranteed before paint, such as:
  • Measuring DOM (tooltip, popover positioning)
  • Preventing layout shift
  • Synchronizing scroll/position
👉 Decision heuristic:
“Will the user see a broken frame before correction?”
If yes → useLayoutEffect.

❌ Weak Answer

“When I need DOM access”
❌ Fails because both hooks have DOM access—timing is the key difference.

2. Explain how useLayoutEffect fits into React’s commit phase.

🔍 Follow-up

  • What happens if it’s slow?
  • Can React interrupt it?

✅ Strong Answer

Order:
  1. DOM mutations applied
  2. useLayoutEffect runs synchronously
  3. Browser paints
  4. useEffect runs asynchronously
  • It blocks paint
  • Cannot be interrupted (even in concurrent mode)

❌ Weak Answer

“It runs before useEffect”
❌ Too shallow—misses lifecycle and blocking behavior.

3. You see UI flicker when positioning a dropdown. How do you debug it?

🔍 Follow-up

  • How would you confirm it’s a timing issue?
  • What tools would you use?

✅ Strong Answer

Steps:
  1. Identify flicker → suspect post-paint update
  2. Check if logic is in useEffect
  3. Move to useLayoutEffect
  4. Verify using DevTools (paint timing)

❌ Weak Answer

“Add delay or debounce”
❌ Treats symptom, not root cause.

4. How can useLayoutEffect cause layout thrashing?

🔍 Follow-up

  • How would you fix it in a large component tree?

✅ Strong Answer

Pattern:
readwriteread
Triggers forced reflow repeatedly. Fix:
  • Batch reads first
  • Then writes

❌ Weak Answer

“Too many re-renders”
❌ Incorrect root cause.

5. What trade-offs exist between useLayoutEffect and CSS solutions?

🔍 Follow-up

  • When would you avoid JS entirely?

✅ Strong Answer

Prefer CSS when:
  • Static layout (flexbox, grid, vh)
Use useLayoutEffect when:
  • Layout depends on runtime measurement

❌ Weak Answer

“CSS is faster”
❌ Oversimplified—misses capability differences.

6. Why is useLayoutEffect problematic in SSR?

🔍 Follow-up

  • How do you design isomorphic code?

✅ Strong Answer

  • No DOM/layout on server
  • React warns because effect has no meaning
Solution:
const useSafeLayoutEffect =
  typeof window !== "undefined"
    ? useLayoutEffect
    : useEffect;

❌ Weak Answer

“It doesn’t work on server”
❌ Lacks explanation and solution.

7. How does useLayoutEffect behave under React Strict Mode?

🔍 Follow-up

  • What kind of bugs does this expose?

✅ Strong Answer

  • Runs twice (setup → cleanup → setup)
  • Exposes:
    • Non-idempotent logic
    • Side effects without cleanup

❌ Weak Answer

“Runs twice for debugging”
❌ Doesn’t explain purpose or implications.

8. You have a drag-and-drop system that feels laggy. It uses useLayoutEffect. What’s wrong?

🔍 Follow-up

  • What would you replace it with?

✅ Strong Answer

  • useLayoutEffect blocks paint on every drag update
  • Causes jank
Fix:
  • Use useEffect + requestAnimationFrame
  • Only use layout effect for initial measurement

❌ Weak Answer

“Optimize code inside effect”
❌ Misses architectural issue.

9. Can useLayoutEffect lead to infinite loops? Explain a real scenario.

🔍 Follow-up

  • How would you guard against it?

✅ Strong Answer

useLayoutEffect(() => {
  setState(value);
}, [state]);
Loop:
  • state update → re-render → effect → update
Fix:
  • Correct dependencies
  • Conditional updates

❌ Weak Answer

“Yes, if dependencies are wrong”
❌ Too generic.

10. How would you design a tooltip system at scale (multiple tooltips, portals, dynamic content)?

🔍 Follow-up

  • How do you avoid repeated measurements?

✅ Strong Answer

  • Centralized positioning logic (hook/context)
  • Measure with useLayoutEffect
  • Cache dimensions
  • Use portals to avoid layout constraints

❌ Weak Answer

“Use useLayoutEffect in each tooltip”
❌ Doesn’t scale.

11. What is the relationship between useLayoutEffect and browser paint?

🔍 Follow-up

  • How does this impact user perception?

✅ Strong Answer

  • Runs before paint → blocks rendering
  • Ensures user sees final layout only
Impact:
  • Better visual stability
  • Risk of slower UI

❌ Weak Answer

“It runs before render”
❌ Incorrect.

12. How do you prevent layout shift when loading dynamic content?

🔍 Follow-up

  • Would you always use useLayoutEffect?

✅ Strong Answer

Options:
  • Reserve space (CSS)
  • Use placeholders
  • Measure and adjust with useLayoutEffect if needed

❌ Weak Answer

“Use useLayoutEffect”
❌ Over-reliance on JS.

13. When measuring DOM, why is useLayoutEffect preferred over useEffect?

🔍 Follow-up

  • What happens if you don’t?

✅ Strong Answer

  • Measurement must reflect final DOM before paint
  • useEffect causes visible mismatch → flicker

❌ Weak Answer

“Because it runs earlier”
❌ Not enough reasoning.

14. How does useLayoutEffect behave with concurrent rendering?

🔍 Follow-up

  • Does it benefit from concurrency?

✅ Strong Answer

  • Still synchronous in commit phase
  • Not interruptible
  • Doesn’t benefit from concurrent rendering

❌ Weak Answer

“It becomes async”
❌ Incorrect.

15. How would you debug a performance issue caused by layout effects?

🔍 Follow-up

  • What metrics/tools?

✅ Strong Answer

  • Chrome Performance tab
  • Look for long tasks before paint
  • Identify heavy layout effects
  • Move non-critical work to useEffect

❌ Weak Answer

“Optimize code”
❌ Too vague.

16. Why is batching state updates important inside useLayoutEffect?

🔍 Follow-up

  • What happens if you don’t?

✅ Strong Answer

  • Multiple setState → multiple renders
  • Even worse since it blocks paint
Fix:
  • Combine into single update

❌ Weak Answer

“For performance”
❌ Missing mechanism.

17. What mental model do you use for deciding between hooks?

🔍 Follow-up

  • Give real-world examples

✅ Strong Answer

  • useEffect → side effects after paint
  • useLayoutEffect → layout-critical sync work
Decision:
“Does this affect what the user sees immediately?”

❌ Weak Answer

“Depends on use case”
❌ Too vague.

18. Can useLayoutEffect replace all useEffect usage? Why or why not?

🔍 Follow-up

  • What happens if you try?

✅ Strong Answer

  • Technically yes, but:
    • Blocks paint
    • Hurts performance
    • Misuses lifecycle

❌ Weak Answer

“No, because React says so”
❌ No reasoning.

19. How would you implement scroll restoration correctly?

🔍 Follow-up

  • Why not useEffect?

✅ Strong Answer

useLayoutEffect(() => {
  window.scrollTo(0, savedY);
}, []);
  • Must happen before paint to avoid visible jump

❌ Weak Answer

“Use useEffect”
❌ Causes flicker.

20. What are signs that a developer is misusing useLayoutEffect?

🔍 Follow-up

  • How would you refactor their code?

✅ Strong Answer

  • Used for:
    • API calls
    • Logging
    • Non-visual logic
Refactor:
  • Move to useEffect
  • Keep layout effects minimal

❌ Weak Answer

“Too many layout effects”
❌ Doesn’t identify misuse.

🔥 Final Evaluation Insight

These questions help identify if a candidate:
  • Understands render → commit → paint pipeline
  • Can make trade-off decisions
  • Thinks in terms of user perception (not just code)
  • Can debug real UI issues