Performant React 101: `useEffect` or `useLayoutEffect`?
Tags: javascript, react, webdev, performance
Published: 2022-05-29 11:27:33

Front-end developers working with React use the `useEffect` hook all the time to render side-effects.
 
But did you know that there is a similar but slightly different hook called `useLayoutEffect`? I didn't, until I stumbled on an instance of this hook used in one of the codebases I was contributing to.

This is a blog to get to the heart of the difference between the two and understand when and when not to use each.

## The difference

In a nutshell the difference is about precision.

- `useEffect` runs but there is no guarantee about exactly when this occurs. It is an **asynchronous** operation that runs after layout and painting of the pixels.

- `useLayoutEffect` in contrast, is guaranteed to run immediately. It is a **synchronous** operation that occurs after all DOM mutations and before the browser can paint the pixels. If you are familiar with the `componentDidMount` lifecycle in React's class components, this is basically the equivalent behaviour.

## useLayoutEffect seems superior. Should we use it for everything?

But why wouldn't we want to use useLayoutEffect all the time?

Not so fast. As with everything, precision has a **cost**.

React has optimised `useEffect` to be more performant. We need to program side-effects a lot when using React and the performance enhancements built into to `useEffect` will materially add up.

The React team explicitly encourages users to use `useEffect` as much as possible to **avoid blocking visual updates**.

In the words of the React official docs under '[Timing of effects](https://reactjs.org/docs/hooks-reference.html#timing-of-effects)':

> … the function passed to useEffect fires after layout and paint, during a deferred event. This makes it suitable for the many common side effects, like setting up subscriptions and event handlers, because most types of work shouldn't block the browser from updating the screen.

**Side note**: The React team recently upgraded `useEffect` in React 18 to make it synchronous for common events such as a user clicks, even less reasons for you to use the `useLayoutEffect` hook.

## So when should we use useLayoutEffect?

This usually boils down to one main reason: 

When you need to **measure the DOM and provide immediate visual feedback** of the calculation (hence the 'Layout' in the name). 

This is important here as side-effects cannot be deferred.

- The React docs gives us [an example where the DOM mutation is calculated before the next paint to ensure that a user does not notice visual inconsistencies](https://reactjs.org/docs/hooks-reference.html#timing-of-effects).

- This could include specific use cases such as animations or moving things around the DOM which requires instant calculations and feedback. Using `useEffect` for these use cases would likely result in a janky and inconsistent experience.

**<u>There is an additional use case: </u>**
- As I mentioned above, `useLayoutEffect` is the equivalent of the old `componentDidMount` lifecycle in React's class components. This hook can be used to help you migrate from class components to function components to give you a one-for-one replacement. However, this should be a temporary fix.

## Takeaways

Think of `useEffect` as your reliable Toyota corolla: reliable, performant and cheap - perfect for 99.9% of use cases. `useLayoutEffect` on the other hand is a high-end Ferrari: fast, responsive, but costly to run reserved for the 0.1% when speed really matters.

- `useEffect` and `useLayoutEffect` is both used to action side-effects, but the latter allows you more precise control when it is run.

- Use useEffect as much as possible to take advantage of the React teams performance optimisations. There are very few genuine use cases for `useLayoutEffect` . Only use if (1) you need to visually show side-effects immediately to your users, or (2) when you are temporarily migrating from `componentDidMount`.