useEffect vs. useLayoutEffect in plain, approachable language
Tags: react, javascript, webdev
Published: 2019-08-08 19:41:01

---
title: useEffect vs. useLayoutEffect in plain, approachable language
published: true
tags: react, javascript, webdev 
canonical_url: https://blog.logrocket.com/useeffect-vs-uselayouteffect/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/msfl92hxjll0f4rq6o4f.jpeg
---
**Written by [Ohans Emmanuel](https://blog.logrocket.com/author/ohansemmanuel/)**✏️

Before you dismiss this as another “basic” React article, I suggest you slow down for a bit.

Assuming you really understand the difference between `useEffect` and `useLayoutEffect`, can you explain this difference in simple terms? Can you describe their nuances with concrete, practical examples?

![Eintstein Quote](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/einstein-explain-six-year-old.png?resize=730%2C386&ssl=1)

Can you?

What you’re about to read is arguably the simplest take on the subject you’ll find anywhere on the internet. I’ll describe the differences between `useEffect` and `useLayoutEffect` with concrete examples that’ll help you cement your understanding for as long as is needed.

Let’s get started.

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## What’s the actual difference between `useEffect` and `useLayoutEffect`?

Sprinkled all over the official [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html) are pointers to the difference between `useEffect` and `useLayoutEffect`.

Perhaps the most prominent of these is found in the first [paragraph](https://reactjs.org/docs/hooks-reference.html#uselayouteffect) detailing the `useLayoutEffect` Hook:

> “The signature is identical to `useEffect`, but it fires synchronously after all DOM mutations.”

The first clause in the sentence above is easy to understand. The signature for both Hooks are identical. The signature for `useEffect` is shown below:

```jsx
useEffect(() => {
  // do something
}, )
```

The signature for `useLayoutEffect` is exactly the same!

```jsx
useLayoutEffect(() => {
  // do something
}, )
```

In fact, if you go through a codebase and replace every `useEffect` call with `useLayoutEffect`, although different, this will work in most cases.

For instance, I’ve taken an example from the [React Hooks Cheatsheet](https://react-hooks-cheatsheet.com/examples/fetching-data) that fetches data from a remote server and changed the implementation to use `useLayoutEffect` over `useEffect`.

![Data Fetching With useLayoutEffect](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/data-fetching-example.gif?resize=730%2C378&ssl=1)

It still works!

So, we’ve established the first important fact here: `useEffect` and `useLayoutEffect` have the same signature. Because of this, it’s easy to assume that these two Hooks behave in the same way. However, the second part of the aforementioned quote above feels a little fuzzy to most people:

> “… it fires synchronously after all DOM mutations.”

The difference between `useEffect` and `useLayoutEffect` is solely _when_ they are fired.

Read on.

## An explanation for a 5-year old

Consider the following contrived counter application:

```jsx
function Counter() {
    const [count, setCount] = useState(0)
    useEffect(() => {
      // perform side effect
      sendCountToServer(count)
    }, [count])
    <div>
        <h1> {`The current count is ${count}`} </h1>
        <button onClick={() => setCount(count => count + 1)}>
            Update Count
        </button>
</div> }
// render Counter
<Counter />
```

When the component is mounted, the following is painted to the user’s browser:

```jsx
// The current count is 0
```

With every click of the button, the counter state is updated, the DOM mutation printed to the screen, and the effect function triggered.

I’ll ask that you stretch your visual imagination for a bit, but here’s what’s really happening:

**1. The user performs an action, i.e., clicks the button.**

**2. React updates the count state variable internally.**

**3. React handles the DOM mutation.**

With the click comes a state update, which in turn triggers a DOM mutation, i.e., a change to the DOM. The text content of the `h1` element has to be changed from “the current count is **_previous value_** ” to “the current count is **_new value_**.”

![State Update Illustration](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/state-update-illustration.png?resize=730%2C290&ssl=1)

**4. The browser paints this DOM change to the browser’s screen.**

Steps 1, 2, and 3 above do _not_ show any visual change to the user. Only after the browser has painted the changes/mutations to the DOM does the user actually see a change; no browser paint, no visual change to the user.

React hands over the details about the DOM mutation to the browser engine, which figures out the entire process of painting the change to the screen. Understanding the next step is crucial to the discussed subject.

**5. Only after the browser has painted the DOM change(s) is the `useEffect` function fired.**

Here’s an illustration to help you remember the entire process.

![Browser Painting Illustration](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/browser-painting-illustration.png?resize=730%2C582&ssl=1)

What to note here is that the function passed to `useEffect` will be fired _only_ after the DOM changes are painted to the screen.

You’ll find the official docs put it this way: the function passed to `useEffect` will run _after the render is committed_ to the screen.

![useEffect Function Illustration](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/useeffect-function-illustration.png?resize=730%2C193&ssl=1)

Technically speaking, the effect function is fired asynchronously not to block the browser paint process. What’s not obvious from the illustration above is that this is still an incredibly fast operation for most DOM mutations. If the `useEffect` function itself triggers another DOM mutation, this happens after the first, but the process is usually pretty fast.

**N.B.:** Although `useEffect` is deferred until after the browser has painted, it’s guaranteed to fire before any new renders. React will always flush a previous render’s effects before starting a new update.

Now, how does this differ from the `useLayoutEffect` Hook?

Unlike `useEffect`, the function passed to the `useLayoutEffect` Hook is fired **synchronously** after all DOM mutations.

![useLayoutEffect Function Illustration](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/uselayouteffect-function-illustration.png?resize=730%2C193&ssl=1)

In simplified terms, `useLayoutEffect` doesn’t really care whether the browser has painted the DOM changes or not. It triggers the function right after the DOM mutations are computed.

While this seems unideal, it is highly encouraged in specific use cases. For example, a DOM mutation that must be visible to the user should be fired synchronously before the next paint. This is so that the user does not perceive a visual inconsistency. I’ll show an example of this later in the article.

Remember, updates scheduled inside `useLayoutEffect` will be flushed synchronously, before the browser has a chance to paint.

## The difference between `useEffect` and `useLayoutEffect` in examples

As stated in the sections above, the difference between `useEffect` and `useLayoutEffect` is in **when they are fired**. Even so, it’s hard to tangibly quantify this difference without concrete examples.

In this section, I’ll highlight three examples that amplify the significance of the differences between `useEffect` and `useLayoutEffect`.

### 1. Time of execution

Modern browsers are fast — very fast. We will employ some creativity to see how the time of execution differs between `useEffect` and `useLayoutEffect`.

In the [first example](https://codesandbox.io/s/useeffect-uselayouteffect-time-of-execution-gtrvg?fontsize=14) we’ll discuss, I have a counter similar to what we considered earlier.

![useEffect Count Example](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/useeffect-count-example-1.png?resize=730%2C497&ssl=1)

What differs in this counter is the addition of two `useEffect` calls.

```jsx
useEffect(() => {
    console.log("USE EFFECT FUNCTION TRIGGERED");
});
useEffect(() => {
    console.log("USE SECOND EFFECT FUNCTION TRIGGERED");
});
```

Note that the effects log different texts depending on which is triggered, and as expected, the first effect function is triggered before the second.

![useEffect Count Example, Part 2](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/useeffect-count-example-2.png?resize=730%2C521&ssl=1)

When there are more than one `useEffect` calls within a component, the order of the effect calls is maintained. The first is triggered, then the second — on and on the sequence goes.

Now, what happens if the second `useEffect` Hook was replaced with a `useLayoutEffect` Hook?

```jsx
useEffect(() => {
    console.log("USE EFFECT FUNCTION TRIGGERED");
});
useLayoutEffect(() => {
    console.log("USE LAYOUT EFFECT FUNCTION TRIGGERED");
});
```

Even though the `useLayoutEffect` Hook is placed after the `useEffect` Hook, the `useLayoutEffect` Hook is triggered first!

![useEffect Count Example, Part 3](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/useeffect-count-example-3.png?resize=730%2C520&ssl=1)

This is understandable. The `useLayoutEffect` function is triggered synchronously, before the DOM mutations are painted. However, the `useEffect` function is called _after_ the DOM mutations are painted.

Does that make sense?

I’ve got one more interesting example with respect to the time of execution for both the `useEffect` and `useLayoutEffect` Hooks.

In the following example, I’ll take you back to college, or any other bittersweet experience you had plotting graphs. ![🙂](https://s.w.org/images/core/emoji/12.0.0-1/72x72/1f642.png)

The example app has a button that toggles the visual state of a title — whether shaking or not. Here’s the app in action:

![Title Shake Example App](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/title-shake-example-app.gif?resize=730%2C577&ssl=1)

The reason I chose this example is to make sure the browser actually has some fun changes to paint when the button is clicked, hence the animation.

The visual state of the title is toggled within a `useEffect` function call. You can [view the implementation](https://codesandbox.io/s/useeffect-uselayouteffect-time-of-execution-2-kqnqp?fontsize=14) if that interests you.

However, what’s important is that I gathered significant data by toggling the visual state on every second, i.e., by clicking the button. This was done with both `useEffect` and `useLayoutEffect`.

Using `performance.now`, I measured the difference between when the button was clicked and when the effect function was triggered for both `useEffect` and `useLayoutEffect`.

Here’s the data I gathered:

![Time Of Evaluation Data Sheet](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/time-of-evaluation-data-sheet.png?resize=730%2C644&ssl=1)

Uninterpreted numbers mean nothing to the visual mind. From this data, I created a chart to visually represent the time of execution for `useEffect` and `useLayoutEffect`. Here you go:

![Time Of Evaluation Graph](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/time-of-evaluation-graph.png?resize=730%2C330&ssl=1)

See how much later `useEffect` is fired when compared to `useLayoutEffect`?

Take your time to interpret the graph above. In a nutshell, it represents the time difference — which in some cases is of a magnitude greater than 10x — between when the `useEffect` and `useLayoutEffect` effect functions are triggered.

You’ll see how this time difference plays a huge role in use cases such as animating the DOM, explained in example 3 below.

### 2. Performing

Expensive calculations are, well, expensive. If treated poorly, these can negatively impact the performance of your application.

With applications that run in the browser, you have to be careful not to block the user from seeing visual updates just because you’re running a heavy computation in the background.

The behavior of both `useEffect` and `useLayoutEffect` are different in how heavy computations are handled. As stated earlier, `useEffect` will defer the execution of the effect function until after the DOM mutations are painted, making it the obvious choice out of the two. (As an aside, I know `useMemo` is great for memoizing heavy computations. This article neglects that fact, and just compares `useEffect` and `useLayoutEffect`.)

Do I have an example that buttresses the point I just made? You bet!

Since most modern-day computers are really fast, I’ve set up an app that’s not practical, but decent enough to work for our use case.

[The app](https://codesandbox.io/s/useeffect-uselayouteffect-time-of-execution-gtrvg?fontsize=14) renders with an initial screen that seems harmless:

![Initial App Render](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/initial-app-render.png?resize=730%2C503&ssl=1)

However, it’s got two clickable buttons that trigger some interesting changes. For example, clicking the **200 bars** button sets the count state to 200.

![App Rendering With Count State of 200](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/app-render-count-state-200.png?resize=730%2C504&ssl=1)

But that’s not all. It also forces the browser to paint 200 new bars to the screen.

![App After Having Rendered 200 Bars](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/app-render-200-bars.png?resize=730%2C504&ssl=1)

Here’s how:

```jsx
... 
return (
...
   <section
        style={{
            display: "column",
            columnCount: "5",
            marginTop: "10px" }}>
        {new Array(count).fill(count).map(c => (
          <div style={{
                height: "20px",
                background: "red",
                margin: "5px"
         }}> {c}
         </div> ))}
   </section>
)
```

This is not a very performant way to render 200 bars, as I’m creating new arrays every single time, but that’s the point: to make the browser work.

Oh, and that’s not all. The click also triggers a heavy computation.

```jsx
...
useEffect(() => {
    // do nothing when count is zero
    if (!count) {
      return;
}
    // perform computation when count is updated.
    console.log("=== EFFECT STARTED === ");
    new Array(count).fill(1).forEach(val => console.log(val));
    console.log(`=== EFFECT COMPLETED === ${count}`);
}, [count]);
```

Within the effect function, I create a new array with a length totaling the count number — in this case, an array of 200 values. I loop over the array and print something to the console for each value in the array.

Even with all this, you need to pay attention to the screen update and your log consoles to see how this behaves.

For `useEffect`, your **screen is updated** with the new count value **before the logs are triggered**.

Here’s a screencast of this in action:

![Logs Triggered With useEffect](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/logs-triggered-useeffect.gif?resize=730%2C506&ssl=1)

If you’ve got eagle eyes, you probably caught that! For the rest of us, here’s the same screencast in [slow-mo](https://youtu.be/M5_RlEn0XKw). There’s no way you’ll miss the screen update happening before the heavy computation!

So is this behavior the same with `useLayoutEffect`? No! Far from it.

With `useLayoutEffect`, the computation will be triggered before the browser has painted the update. Since the computation takes some time, this eats into the browser’s paint time.

Here’s the same action performed with the `useEffect` call replaced with `useLayoutEffect`:

![Logs Triggered With useLayoutEffect](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/logs-triggered-uselayouteffect.gif?resize=730%2C507&ssl=1)

Here it is in [slow-mo](https://youtu.be/irUvYd39k4c). You can see how `useLayoutEffect` stops the browser from painting the DOM changes for a bit. You can play around with [the demo](https://codesandbox.io/s/useeffect-vs-uselayouteffect-heavy-computation-zoi53?fontsize=14), but be careful not to crash your browser.

Why does this difference in how heavy computations are handled matter? Where possible, choose the `useEffect` Hook for cases where you want to be unobtrusive in the dealings of the browser paint process. In the real world, this is usually most times! Well, except when you’re reading layout from the DOM or doing something DOM-related that needs to be painted ASAP.

The next section shows an example of this in action.

### 3. Inconsistent visual changes

This is the one place where `useLayoutEffect` truly shines. It’s also slightly tricky to come up with an example for this.

However, consider the following screencasts. With `useEffect`:

![Visual Changes With useEffect](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/visual-changes-useeffect.gif?resize=730%2C447&ssl=1)

With `useLayoutEffect`:

![Visual Changes With useLayoutEffect](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/visual-changes-uselayouteffect.gif?resize=730%2C447&ssl=1)

These were real scenarios I found myself in while working on my soon-to-be released [Udemy video course](https://forms.gle/Qd6yZC1Lhcosnc2f8) on Advanced Patterns with React Hooks.

The problem here is that with `useEffect`, you get a flicker before the DOM changes are painted. This was related to how refs are passed on to custom Hooks (i.e., Hooks you write). Initially, these refs start off as `null` before actually being set when the attached DOM node is rendered.

If you rely on these refs to perform an animation as soon as the component mounts, then you’ll find an unpleasant flickering of browser paints happen before your animation kicks in. This is the case with `useEffect`, but not `useLayoutEffect`.

Even without this flicker, sometimes you may find `useLayoutEffect` produces animations that look buttery, cleaner and faster than `useEffect`. Be sure to test both Hooks when working with complex user interface animations.

## Conclusion

Phew! What a long discourse that turned out to be! Anyway, you’ve been armed with good information here. Go build performant applications and use the desired hook where needed.

Want to see my (new) take on Advanced React Patterns with Hooks? Sign up for the [waiting list](https://forms.gle/Qd6yZC1Lhcosnc2f8)!
* * *
**Editor's note:** Seeing something wrong with this post? You can find the correct version [here](https://blog.logrocket.com/useeffect-vs-uselayouteffect/).

## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
[Try it for free](https://logrocket.com/signup/).
* * *
The post [useEffect vs. useLayoutEffect in plain, approachable language](https://blog.logrocket.com/useeffect-vs-uselayouteffect/) appeared first on [LogRocket Blog](https://blog.logrocket.com).