We're planting a tree for every job application! Click here to learn more

What is useLayoutEffect Hook & how it compares to useEffect?

Abhinav Anshul

13 Dec 2021

5 min read

What is useLayoutEffect Hook & how it compares to useEffect?
  • JavaScript

React Hooks were released a couple of years ago when React ecosystem introduced a new way to handle state and effects in a function-based component. Although there isn't any sudden plan to completely deprecate the class-based approach, however, web applications have been moving to hooks rapidly. In this article, we'll look into the useLayoutEffect hook and its similarities & differences with the useEffect hook.

A side-effect hook

Before we dive into useLayoutEffect, it is worth mentioning that both this and the useEffect hook is used to handle side-effects in React.

Another way of saying this would be when the DOM paints the screen, we want to do some activity called side-effects that could include data fetching, updating and changing DOM elements, subscribing to an event etc.

What is useLayoutEffect?

According to the official docs,

"The signature is identical to useEffect, but it fires synchronously after all DOM mutations."

As it has two parts, let's look at the first statement, "signature is identical to useEffect",

useEffect and useLayoutEffect shares similar function signatures, meaning the API exposed to the developers are similar in both cases.

Given below is a simple counter application using useEffect that increments the count on a button click and prints the value using effect hook in the console.


function App(){

 const [count, setCount] = React.useState('0')

  React.useEffect(() => {

    console.log(count)

  }, [count])

  

return(

 <div>

  <h1>The count is {count} </h1>

  <button onClick={() => setCount(count + 1)}></button

 </div>

 )

}

If we replace useEffect hook with this instead,


React.useLayoutEffect(() => {

  console.log(count)

}, [count])

  

The Counter app would still work the same, this establishes the fact about having identical function signatures as,


useLayoutEffect(() => {

 // run effect here

}, [<dependency array>])

One thing to note here, it also returns either a cleanup function or an undefined value similar to the useEffect hook.

Moving onto the next statement, "but it fires synchronously after all DOM mutations.", this is where useLayoutEffect differentiates itself from useEffect hook, by the order in which they are fired.

In the above useEffect counter example, here's how React is rendering the function and handling interactivity:

a. When the App component gets mounted to the screen, the default count value 0 is printed along with the HTML button.


The count is 0.

b. The user clicks on the button and increments the count value by 1.

c. React triggers the state value of the count mentioned in the useState hook, and re-renders the count value.

d. After the DOM is done with painting the screen with mutated value, useEffect hook is triggered.

In a nutshell, a useEffect hook only gets triggered once DOM is done painting the screen, making it asynchronous as it doesn't block the DOM manipulation on the screen.

However, things gets a little more interesting with useLayoutEffect. It gets triggered synchronously. In other words, it doesn't care if the DOM has painted the screen.

We'll deep dive into its working below:

1. Execution Order

As we have seen, useLayoutEffect doesn't wait for DOM to paint the screen and gets fired right away. This sure affects the order of execution.

In a useEffect hook,


useEffect(() => {

  console.log("log 1")

}, [])

  

useEffect(() => {

  console.log("log 2")

}, [])

The code prints:


log 1

log 2

This is an expected behaviour while working with useEffect. It executes in the order in which they were mentioned.

Now, let's replace the second hook with a useLayoutEffect :


useEffect(() => {

  console.log("log 1")

}, [])

  

useLayoutEffect(() => {

  console.log("log 2")

}, [])

  

The above prints,


log 2

log 1

As expected, the useLayoutEffect doesn't care for DOM mutation hence gets executed even before the useEffect hook.

2. Performance

The official React doc suggests using the useEffect hook as much as possible and there is a 99% per cent chance it will suit most of the use cases in any application.

As useLayoutEffect is synchronous, React waits for it to finish then updates the screen.

As of rule of thumb, you can think of it as an App component that would wait to get visually updated until the useLayoutEffect has been finished running.

This pauses the React component for a split second, as it is "waiting" for something to be finished, this behaviour might cause a performance hiccup.

Hence performance-wise, useLayoutEffect can be expensive to run.

3. Visual Incosistencies

In complex user interaction which involves animations, it is possibly better to use useLayoutEffect instead of useEffect especially if you're dealing with ref


React.useLayoutEffect(() => {

  console.log(ref.current)

})

In the above, contrived example, useLayoutEffect ensures to wait, updates its value then move on to the other piece of code. This might improve on the animation flickering which usually happens with the useEffect hook.

This is a tradeoff between running expensive hook v/s having a smooth animation. However, React is fast enough to optimize on small use cases and we won't be bothered between the two at all.

4. useLayoutEffect & SSR

There's an infamous useLayoutEffect warning,

"Warning: useLayoutEffect does nothing on the server because its effect cannot be encoded into the server renderer's output format..."

When dealing with SSR, both useEffect & useLayoutEffect won't work unless that JavaScript has been properly loaded. Therefore, there's the above warning we might see in the console. The reason why it doesn't generate with useEffect is, it is not concerned with the render cycle of the component unlike useLayoutEffect is concerned and cares what users would see on the very first render of the component.

React Community suggests two ways to fix this,

1. Of course, the first thing we can do is to try to convert it to a useEffect hook if possible.

2. If there is a flickering issue with the useEffect (as we discussed earlier ) and developers do need useLayoutEffect, then another way could be delaying that very component that uses the hook until the JavaScript has been loaded. Another way of saying, lazily load the React Component.

Wrapping Up

In this post, we read how similar useEffect & useLayoutEffect can appear to be. However, the order in which both these hooks gets called is completely different. In small scale applications, both might look interchangeable but the latter shines while dealing with complex user animations, handling refs in React, dealing with Layout on a page etc. Although useLayoutEffect can be a little expensive to deal with compared to the useEffect hook, there are always tradeoffs while building applications. Finally, we learnt about how to use it with an SSR based application.

Some Important Resources that I have collected over time:

  1. https://reactjs.org/docs/hooks-reference.html#uselayouteffect
  2. https://kentcdodds.com/blog/useeffect-vs-uselayouteffect
  3. https://blog.bhanuteja.dev/the-lifecycle-of-react-hooks-component
  4. https://stackoverflow.com/questions/66148855/is-uselayouteffect-preferable-to-useeffect-when-reading-layout
  5. https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85

Loved this post? Have a suggestion or just want to say hi? Reach out to me on Twitter

Did you like this article?

Abhinav Anshul

(づ ◕‿◕ )づ

See other articles by Abhinav

Related jobs

See all

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Related articles

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

WorksHub

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works
hello@works-hub.com

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

Join over 111,000 others and get access to exclusive content, job opportunities and more!

© 2024 WorksHub

Privacy PolicyDeveloped by WorksHub