useEffect and useLayoutEffect hooks in React.js

Both useEffect and useLayoutEffect are hooks provided by React for managing side effects in functional components. While they are similar in many ways, there are important differences in when they are executed relative to the render cycle. Here's a breakdown of the differences:

Timing of Execution

  • useEffect: Runs after the browser has painted and after the component has been rendered. It is scheduled by React after the render is committed to the screen.
  • useLayoutEffect: Runs synchronously after the DOM has been updated, but before the browser has painted. It is scheduled by React after the render but before the browser has had a chance to paint.

Scheduling

  • useEffect: Asynchronous. It doesn't block painting or other browser activities. It's typically used for side effects that don't need to be synchronous with the DOM updates.
  • useLayoutEffect: Synchronous. It blocks painting until it finishes its execution. It's useful when you need to make DOM measurements or perform actions that depend on the DOM being in a certain state.

Performance Considerations

  • useEffect: Generally more performant because it doesn't block the browser's rendering pipeline. It's suitable for most side effects that don't require immediate DOM mutations.
  • useLayoutEffect: Less performant due to its synchronous nature, especially if the code inside it is complex or time-consuming. It should be used sparingly and only when necessary for specific layout-related tasks.

Here's an example to illustrate the usage of both hooks.

import React, { useEffect, useLayoutEffect, useState } from 'react';

const MyComponent = () => {
  const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });

  // useEffect example
  useEffect(() => {
    const handleResize = () => {
      setSize({ width: window.innerWidth, height: window.innerHeight });
    };
    window.addEventListener('resize', handleResize);
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []); // Run only on mount and unmount

  // useLayoutEffect example
  useLayoutEffect(() => {
    document.title = `Width: ${size.width}, Height: ${size.height}`;
  }, [size]); // Run whenever size changes

  return (
    <div>
      <p>Window Width: {size.width}</p>
      <p>Window Height: {size.height}</p>
    </div>
  );
};

export default MyComponent;

In this example

  • useEffect is used to update the component state when the window is resized. It runs after the render is committed to the screen.
  • useLayoutEffect is used to update the document title synchronously whenever the size state changes. It runs before the browser repaints.