How to Update useLayoutEffect Hook in React

The useLayoutEffect hook in React is a powerful tool for performing DOM mutations synchronously before the browser repaints the screen. This article explains how to correctly update and trigger the useLayoutEffect hook by managing its dependency array, updating state within it, and modifying your codebase safely for server-side rendering environments.

Updating via the Dependency Array

To make useLayoutEffect run again when specific data changes, you must update its dependency array. Like useEffect, useLayoutEffect accepts a second argument containing an array of variables. React compares the current values of these dependencies with their values from the previous render. If any value has changed, the hook runs again.

import { useLayoutEffect, useState, useRef } from 'react';

function ResizableBox({ content }) {
  const [height, setHeight] = useState(0);
  const elementRef = useRef(null);

  useLayoutEffect(() => {
    if (elementRef.current) {
      // Re-runs and updates the height state whenever 'content' changes
      setHeight(elementRef.current.getBoundingClientRect().height);
    }
  }, [content]); // Dependency array containing 'content'

  return (
    <div ref={elementRef}>
      {content}
    </div>
  );
}

If you leave the dependency array empty ([]), the hook will only run once when the component mounts. If you omit the dependency array entirely, the hook will run after every single render.

Updating State Inside useLayoutEffect

You can update React state inside useLayoutEffect to fix visual glitches. Because useLayoutEffect runs synchronously before the browser paints, any state updates triggered inside it are processed before the user sees the screen. This prevents the visual “flicker” that often happens when updating state inside the standard useEffect hook.

However, use this pattern with caution. Because the browser waits for useLayoutEffect to finish, performing heavy computations or triggering excessive state updates inside this hook will delay painting and make your application feel sluggish.

Updating for Server-Side Rendering (SSR)

If you are updating a React application to use Server-Side Rendering (SSR) frameworks like Next.js, using useLayoutEffect directly will trigger console warnings. This is because the server does not have access to the window or DOM layout when rendering the initial HTML.

To update and resolve this issue, you can conditionally use useEffect on the server and useLayoutEffect on the client:

import { useEffect, useLayoutEffect } from 'react';

// Use useLayoutEffect on the client, fall back to useEffect on the server
const useSafeLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;

function MyComponent() {
  useSafeLayoutEffect(() => {
    // DOM-related measurements go here safely
  }, []);
}

Updating your code to use this custom wrapper ensures your application builds successfully on the server while retaining synchronous layout measurements on the client.