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.
In a nutshell the difference is about precision.
useEffectruns but there is no guarantee about exactly when this occurs. It is an asynchronous operation that runs after layout and painting of the pixels.
useLayoutEffectin 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
componentDidMountlifecycle in React's class components, this is basically the equivalent behaviour.
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
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.
This could include specific use cases such as animations or moving things around the DOM which requires instant calculations and feedback. Using
useEffectfor these use cases would likely result in a janky and inconsistent experience.
There is an additional use case:
- As I mentioned above,
useLayoutEffectis the equivalent of the old
componentDidMountlifecycle 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.
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.
useLayoutEffectis 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