useLayoutEffect vs useEffect

January 07, 2021

A post by Will Mayger
Twitter . Instagram

In this post we are going to cover what both useEffect and useLayoutEffect do, why they are different and when you should use each one.

As with all my posts, this will be written in plain english whilst trying to avoid as much technical jargon as possible so that all experience levels can understand the differences between useLayoutEffect and useEffect.

Before we get started, for anyone looking for a quick and simple answer:

Both of these react hooks do a similar thing and work the same way.

The difference comes from where useLayoutEffect will be called before the user can see the visual changes in that render whereas useEffect will be called after a user is able to see the visual changes in that render.

We will go into more detail about what that means a little later on.

For now let’s start by taking a quick look at a useLayoutEffect example as well as a useEffect example:

import React, { useLayoutEffect, useEffect } from "react"
// useLayoutEffect - gets called before user can see visual changes
useLayoutEffect(() => {
  window.title = "test title using useLayoutEffect"
}, [])

// useEffect - gets called after user can see visual changes
useEffect(() => {
  window.title = "test title using useEffect"
}, [])

What are the similarities between useLayoutEffect vs useEffect?

The react hooks useLayoutEffect and useEffect are actually identical in terms of how you use them and what they do - their signatures are identical.

So to answer the question, very similar - there is only one key difference between the two that sets them apart.

These hooks enable you to perform actions in your react components that will be conditionally run in order to avoid running them on every render which would end up being pretty expensive.

Talking specifically about useEffect now, it is kind of your bread and butter (one of the main react hooks you will use) within react along with useState.

You will use the useEffect hook to perform async calls to api’s, set state, use timers, subscriptions, and mutations amongst other things.

In other words if you have some code that you only want to run on occasion, for example, on the first render, or when a prop changes then you will want to use useEffect to be able to do it.

Here is an example of using useEffect:

import React, { useEffect, useState } from "react"

function ExampleComponent() {
  const [message, setMessage] = useState("")

  useEffect(() => {
    if (message === "") {
      setMessage("Hello world")
    }
  }, [message])

  return <p>{message}</p>
}

As you can see we have our hook useEffect, then we are providing it with two things, a callback function, and a dependency array.

The callback function will contain all the code you want to run as well as the conditions of when they should run (if needed).

The dependency array is an array of variables that useEffect can use to conditionally run your callback.

What happens when this hook gets called is react will compare each item in the dependency array to the previous version of it.

If the two have referential equality (identical when compared) then the callback will not be called, however if they do not match then the callback will be called.

Here is a quick example of referential equality:

// referential equality
1 === 1 // equals true
() => {} === () => {} // equals false

const a = () => {}
a === a // equals true

To cover useEffect, and dependency arrays in full, I highly recommend reading these articles I have previously written around the subject:

  1. What is the difference between useMemo and useCallback? - Dependency array and referential equality explanations
  2. How to use setState from within useEffect
  3. Using componentDidMount in react hooks

What are the differences between useLayoutEffect vs useEffect?

Now, let’s talk about the differences between these two hooks.

At the start of this post I said how useEffect will run after the user can interact with the page and useLayoutEffect will run before the user can interact with the page, let’s look at that in a little more detail and understand what that really means for your code.

useLayoutEffect

The useLayoutEffect react hook will run synchronously after DOM mutations have finished but before the page has painted (updated) for the user to be able to see and interact with, this is the same as componentDidMount when using class components.

This means that if you use useLayoutEffect, the code inside the callback will have to be run before the user can see any updates which means that it actually blocks visual updates for the user, until that code has finished running.

Because of this, for the most part, you will always want to use useEffect over useLayoutEffect.

The only time you would want to use useLayoutEffect over useEffect is when you need to make a DOM mutation (update the page) within the effect.

But even then, it is recommended that you start by using useEffect, and only if there is an issue should you then go on to try useLayoutEffect instead.

useEffect

Now, useEffect, on the other hand, will run after the page has been painted and visual changes have already been made that the user can interact with.

This means that when you use useEffect, it will not block visual changes and will often provide a better experience for the user because they do not have to wait for the code within the callback of the effect to finish running before they can see the changes of the render.

Summary of when you should use useLayoutEffect vs useEffect

You should always start by using useEffect, and most of the time you will be able to just leave it there.

If you are making a DOM mutation and there is an issue with useEffect, for example the UI quickly changes from one thing to another, where useEffect loads in after visual changes, only then should you consider switching to useLayoutEffect.

Finally to help remember the differences between useLayoutEffect vs useEffect:

  • useLayoutEffect: After DOM mutations, but before visual changes and before browser painting. This means the user has to wait for your code.
  • useEffect: After DOM mutations, after visual changes and after the browser has painted. This means the user does not have to wait for your code.

I hope you have enjoyed reading this article and that it has been helpful!

Be sure to take a look at some of my other posts!

Will

Image icon made by Freepik from www.flaticon.com