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 thecomponentDidMount
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':
… 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.
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.
There is an additional use case:
- As I mentioned above,
useLayoutEffect
is the equivalent of the oldcomponentDidMount
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
anduseLayoutEffect
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 fromcomponentDidMount
.
Top comments (0)