When to useLayoutEffect Instead of useEffect

By Dave Ceddia Comment

When to useLayoutEffect Instead of useEffect

There are two React hooks, useEffect and useLayoutEffect, that appear to work pretty much the same.

The way you call them even looks the same.

useEffect(() => {
  // do side effects
  return () => /* cleanup */
}, [dependency, array]);

useLayoutEffect(() => {
  // do side effects
  return () => /* cleanup */
}, [dependency, array]);

But they’re not quite the same. Read on for what makes them different and when to use each. (tl;dr: most of the time you want plain old useEffect)

The Difference Between useEffect and useLayoutEffect

It’s all in the timing.

useEffect runs asynchronously and after a render is painted to the screen.

So that looks like:

  1. You cause a render somehow (change state, or the parent re-renders)
  2. React renders your component (calls it)
  3. The screen is visually updated
  4. THEN useEffect runs

useLayoutEffect, on the other hand, runs synchronously after a render but before the screen is updated. That goes:

  1. You cause a render somehow (change state, or the parent re-renders)
  2. React renders your component (calls it)
  3. useLayoutEffect runs, and React waits for it to finish.
  4. The screen is visually updated

99% of the time, useEffect

Most of the time your effect will be synchronizing some bit of state or props with something that doesn’t need to happen IMMEDIATELY or that doesn’t affect the page visually.

Like if you’re fetching data, that’s not going to result in an immediate change.

Or if you’re setting up an event handler.

Or if you’re resetting some state when a modal dialog appears or disappears.

Most of the time, useEffect is the way to go.

When to useLayoutEffect

The right time to useLayoutEffect instead? You’ll know it when you see it. Literally ;)

If your component is flickering when state is updated – as in, it renders in a partially-ready state first and then immediately re-renders in its final state – that’s a good clue that it’s time to swap in useLayoutEffect.

Here’s a (contrived) example so you can see what I mean.

When you click the page*, the state changes immediately (value resets to 0), which re-renders the component, and then the effect runs – which sets the value to some random number, and re-renders again.

The result is that two renders happen in quick succession.

import React, {
  useState,
  useLayoutEffect
} from 'react';
import ReactDOM from 'react-dom';

const BlinkyRender = () => {
  const [value, setValue] = useState(0);

  useLayoutEffect(() => {
    if (value === 0) {
      setValue(10 + Math.random() * 200);
    }
  }, [value]);

  console.log('render', value);

  return (
    <div onClick={() => setValue(0)}>
      value: {value}
    </div>
  );
};

ReactDOM.render(
  <BlinkyRender />,
  document.querySelector('#root')
);

* In general, putting onClick handlers on divs is bad for accessibility (use buttons instead!), but this is a throwaway demo. Just wanted to mention it!

Try the useLayoutEffect version and then try the version with useEffect.

Notice how the version with useLayoutEffect only updates visually once even though the component rendered twice. The useEffect version, on the other hand, visually renders twice, so you see a flicker where the value is briefly 0.

Should I useEffect or useLayoutEffect?

Most of the time, useEffect is the right choice. If your code is causing flickering, switch to useLayoutEffect and see if that helps.

Because useLayoutEffect is synchronous a.k.a. blocking a.k.a. the app won’t visually update until your effect finishes running… it could cause performance issues if you have slow code in your effect. Coupled with the fact that most effects don’t need the world to pause while they run,

Learning React can be a struggle -- so many libraries and tools!
My advice? Ignore all of them :)
For a step-by-step approach, read my book Pure React.

Best thing that ever happened to my career 👏🏽

I’m very happy I bought this. Didn’t fully grasp the fundamentals from Udemy courses I’ve been taking. I’m buying the Redux course immediately after I’m done with this. THANK YOU SOO MUCH

– Oluwafemi
comments powered by Disqus