useEffect vs useLayoutEffect: When to Use Each Correctly
One of the most confusing parts of working with React Hooks is having two hooks with almost identical syntax: useEffect and useLayoutEffect. Without understanding how they work under the hood, it’s easy to pick the wrong one and accidentally cause flickering or slow down your entire app. This article breaks each hook down so you can make the right call in every situation.

Trung Vũ Hoàng
Author
1. What Are Side Effects in React?
Before we compare them, let’s clarify the notion of Side Effects. These are tasks that occur outside React’s render flow, such as fetching data via APIs, directly manipulating the DOM, or setting up subscriptions to external events.
Both useEffect and useLayoutEffect exist to handle these tasks — the key difference lies in the timing of when they run relative to the browser’s paint cycle.
2. How They Work: Asynchronous vs Synchronous
useEffect — The Performance-Friendly Hook
useEffect is the default choice and suits most cases. The sequence looks like this:
React detects a state change.
React re-renders the component.
The browser paints the updated UI.
useEffect now runs.
Because the callback is invoked after the screen has finished updating, useEffect does not block the browser — keeping the UI responsive and smooth for users.
useLayoutEffect — The Visual-Accuracy-First Hook
By contrast, useLayoutEffect wedges itself in before the browser paints:
React detects a state change.
React re-renders the component.
useLayoutEffect runs immediately (synchronously).
The browser is then allowed to paint.
This means any changes you make inside useLayoutEffect are applied before the user can see any rendered result.
3. Detailed Comparison
Here are the most important criteria to tell these two hooks apart:
Execution timing
useEffect: Runs after the browser has painted the UI (After Paint).
useLayoutEffect: Runs before the browser paints the UI (Before Paint).
Execution type
useEffect: Asynchronous (Async) — does not block rendering.
useLayoutEffect: Synchronous (Sync) — blocks rendering until it finishes.
Performance impact
useEffect: Friendly to page load speed, no interruptions.
useLayoutEffect: Can cause the page to "freeze" if heavy work is done inside.
Typical use cases
useEffect: API calls, Analytics, Event listeners — anything that doesn’t need to happen before paint.
useLayoutEffect: Measuring DOM size, adjusting element positions — things users must see correctly on the very first frame.
4. When Do You Actually Need useLayoutEffect?
Although React officially recommends prioritizing useEffect, there are situations where useLayoutEffect is the only way to avoid a poor user experience.
Scenario 1: Prevent UI Flicker
Suppose you need to compute the exact position of a Tooltip based on the button’s actual size:
With useEffect: The Tooltip appears in its old position → The browser paints → useEffect recalculates → Re-render → The Tooltip "jumps" to the new spot. Users clearly see the jank.
With useLayoutEffect: The position is computed before the browser paints. The Tooltip appears in the correct place from the start, with no visible jitter.
Scenario 2: Measuring DOM Size
When using getBoundingClientRect() or other DOM measurement APIs to build complex layouts, useLayoutEffect ensures the values you read reflect the actual DOM state — before users see the final result.
5. Execution Order in Practice
Consider the snippet below to see the priority clearly:
useLayoutEffect(() => {
console.log("1. useLayoutEffect runs");
}, [count]);
useEffect(() => {
console.log("2. useEffect runs");
}, [count]);
Whenever count changes, the console always prints 1 before 2 — regardless of the order you declare them in the component. This priority is fixed and guaranteed by React.
6. Golden Rules for Choosing a Hook
From real-world product development: Always start with useEffect. Switch to useLayoutEffect only when you observe flicker or visual misalignment.
Overusing useLayoutEffect undermines React Concurrent Mode’s render optimizations, preventing your app from taking advantage of splitting and prioritizing work per frame.
Note for Next.js and SSR: When working with Server-Side Rendering, avoid using
useLayoutEffectat the top-level component because the server has no DOM — this will trigger a build warning and can cause hydration issues.
7. Conclusion
Mastering the difference between useEffect vs useLayoutEffect is a hallmark of a seasoned React developer. A simple rule of thumb:
useEffect→ Prioritizes performance, runs after paint.useLayoutEffect→ Prioritizes visual accuracy, runs before paint.
Understanding this not only helps you ace interview questions but also build truly high-quality React applications.
Frequently Asked Questions
Bài viết liên quan

Zustand Async: 5 Effective Ways to Handle Async in React
Every real-world React app needs to communicate with async APIs. If handled poorly, it’s easy to run into issues like frozen UI, race conditions, memory leaks, or showing stale data. Zustand solves this with an extremely simple syntax—define async actions directly in the store, without complex middleware like Redux Thunk or Saga.

Advanced Promises: all, allSettled, race, any — When to Use Which?
If you only use sequential async/await, your app is wasting performance potential — each request has to wait for the previous one to finish before it can start. Promise’s static methods (all, allSettled, race, any) let you orchestrate multiple async tasks in parallel using the strategy that fits each problem.

Zustand Async: 5 Effective Ways to Handle Async Operations in React
Every real-world React app has to communicate with asynchronous APIs. If managed poorly, your app can run into issues like a frozen UI, race conditions, memory leaks, or showing stale data. Zustand solves this with an incredibly simple syntax — define async actions directly in the store, without complex middleware like Redux Thunk or Saga.