Lesson 8 — useLayoutEffect vs useEffect (When Timing Matters)

🧭 Introduction

Most React developers use useEffect daily — but very few understand when it runs and why timing matters.

You may have seen:

  • UI flickering
  • Incorrect element measurements
  • Animations jumping
  • Layout glitches

And the common (but wrong) solution:

“Let’s try useLayoutEffect everywhere.”

❌ That causes performance problems.

In this lesson, you’ll learn:

  • The exact timing difference between useEffect and useLayoutEffect
  • When useLayoutEffect is required
  • When it is dangerous
  • How senior developers decide between them

🎯 What You’ll Learn in This Lesson

By the end of this lesson, you will understand:

  • When useEffect runs in the render cycle
  • When useLayoutEffect runs
  • Visual vs non-visual side effects
  • Real-world use cases for each
  • Best practices and common mistakes

🔄 The React Rendering Timeline (Critical)

To understand this lesson, you must know this sequence:

1️⃣ React renders component
2️⃣ React commits changes to the DOM
3️⃣ Browser paints UI on screen
4️⃣ useEffect runs

Now compare with useLayoutEffect.


⏱ When useLayoutEffect Runs

useLayoutEffect runs earlier:

1️⃣ React renders component
2️⃣ React commits changes to the DOM
3️⃣ useLayoutEffect runs (before paint)
4️⃣ Browser paints UI

👉 This timing difference is everything.


🧠 Key Difference (One Line Summary)

useEffect runs after paint
useLayoutEffect runs before paint


🧩 useEffect (Default Choice)

useEffect is for:

  • Data fetching
  • Subscriptions
  • Logging
  • Non-visual side effects

Example:

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

React paints UI first, then runs the effect.


🧩 useLayoutEffect (Special Case)

useLayoutEffect is for:

  • Reading layout values
  • Measuring DOM elements
  • Applying synchronous layout changes

Example:

useLayoutEffect(() => {
  const height = ref.current.offsetHeight;
}, []);

React waits until this effect completes before painting UI.


⚠ Why Blocking Paint Is Dangerous

Because:

  • Browser cannot show UI until effect finishes
  • Heavy logic blocks rendering
  • App feels slow or frozen

👉 That’s why useLayoutEffect must be used sparingly.


🔍 Real-World Example — Measuring DOM (Correct Use)

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

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

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

Why useLayoutEffect?

  • Measurement must happen before paint
  • Prevents visible layout jump

🔍 Same Example with useEffect (Problematic)

useEffect(() => {
  setWidth(ref.current.offsetWidth);
}, []);

Result:

  • UI paints first
  • Then width updates
  • Causes visual flicker

🎨 Animations & Layout Sync

When:

  • Applying animations
  • Adjusting position
  • Syncing scroll

👉 useLayoutEffect ensures changes happen before user sees UI.


🧠 Decision Rule (Senior-Level Insight)

Use this rule:

❓ Does this effect read or modify layout?

  • ❌ No → useEffect
  • ✅ Yes → useLayoutEffect

🆚 useEffect vs useLayoutEffect (Quick Table)

FeatureuseEffectuseLayoutEffect
Runs after paint✅ Yes❌ No
Blocks UI❌ No✅ Yes
Default choice✅ Yes❌ No
Layout measurement❌ No✅ Yes
Performance safe✅ Yes⚠️ Use carefully

🚨 Common Mistakes (Very Important)

❌ Mistake 1: Replacing all useEffect with useLayoutEffect

This causes unnecessary UI blocking.


❌ Mistake 2: Doing heavy logic in useLayoutEffect

Never fetch data or run long computations here.


❌ Mistake 3: Using useLayoutEffect without DOM access

If no layout is involved, it’s unnecessary.


🧠 SSR Warning (Advanced Insight)

In Server-Side Rendering (SSR):

  • useLayoutEffect does nothing on server
  • React shows warnings

Solution:

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

Or use an isomorphic layout effect pattern.


🎯 Best Practices

✅ Default to useEffect
✅ Use useLayoutEffect only for layout reads/writes
✅ Keep layout effects short
✅ Never fetch data in useLayoutEffect


❓ FAQs — useLayoutEffect vs useEffect

🔹 Is useLayoutEffect faster?

No. It blocks paint, so it can feel slower.


🔹 Should beginners avoid useLayoutEffect?

Yes — until they understand rendering timing.


🔹 Can I replace animations with CSS instead?

Often yes — CSS animations are better.


🔹 Is useLayoutEffect required often?

No. It’s a niche hook.


🧠 Quick Recap

✔ useEffect runs after paint
✔ useLayoutEffect runs before paint
✔ Layout reads require useLayoutEffect
✔ Blocking paint is expensive
✔ Default to useEffect


🎉 Conclusion

Understanding when effects run changes how you design UI.

From now on:

  • You won’t blindly use useLayoutEffect
  • You’ll fix layout flickers correctly
  • You’ll write smoother, professional UIs

This lesson completes your Advanced Hooks mastery ⚛️🧠


👉 Next Section

SECTION 3 — Custom Hooks Mastery
Lesson 9 — What Makes a Good Custom Hook

Leave a Comment