Difference between useLayoutEffect and useEffect

The more I read React documentation at the official website, the more I get confused. That is probably because I don't understand some of the terminology there.

The most recent confusion was me trying to understand the difference between useEffect and useLayoutEffect. According to the docs, useLayoutEffect is similar to the componentDidUpdate method in the React Component class. So, that runs synchronously when updates to virtual DOM is completed and before React commits those changes to the browser.

useEffect is however preferred. It is because it runs asynchronously. It is non-blocking. The code in useEffect hook usually runs after React commits updates to the browser.

So, I set up a CodeSandbox to help me understand if that was the case.

Screenshot 2021-08-22 at 6.31.00 PM.png

I set two buttons - useEffect and useLayoutEffect. Clicking useEffect button changes the title color from default red to green. And clicking useLayoutEffect button changes the title color to blue.

export default function App() {
  const [color, setColor] = useState("red");
  const [time, setTime] = useState(0);

  return (
    <div className="App">
      <h1 style={{ color }}>Hello CodeSandbox</h1>
      <p>Took {time} ms</p>
      <button
        onClick={() => {
          setColor("red");
          setTime(0);
        }}
      >
        Reset
      </button>
      <button onClick={() => setColor("blue")}>useLayoutEffect</button>
      <button onClick={() => setColor("green")}>useEffect</button>
    </div>
  );
}

I monitor the color change in useLayoutEffect. If the color changes to blue, then I run an expensive computation.

  useLayoutEffect(() => {
    if (color === "blue") {
      const time1 = new Date();
      calculatePrimes(iterations, multiplier);
      const time2 = new Date();
      setTime(time2 - time1);
    }
  }, [color]);

Similarly, the useEffect hook watches for color change to green and runs an expensive computation.

useEffect(() => {
    if (color === "green") {
      const time1 = new Date();
      calculatePrimes(iterations, multiplier);
      const time2 = new Date();
      setTime(time2 - time1);
    }
  }, [color]);

The results are according to the docs. For "useLayoutEffect button" click, the color changes from red to blue after 3 seconds because of the expensive computation in useLayoutEffect hook. Whereas when we click "useEffect button", the color changes from red to green instantaneously though the expensive operation in useEffect hook ran for 3 seconds.

By the way, for the expensive computation, I used MDN's calculatePrimes method. So, acknowledging them for that awesome function.

The example is available in CodeSandbox for you to try it out.