React Course
React
/
Advanced

useLayoutEffect

Definition

The signature is identical to `useEffect`, but it fires synchronously after all DOM mutations. Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside `useLayoutEffect` will be flushed synchronously, before the browser has a chance to paint.

Explain Like I'm New

Imagine the browser is an artist painting a screen. `useEffect` lets the artist finish painting the screen so the user can see it, and THEN runs your code in the background. `useLayoutEffect` grabs the artist's hand right before they put the paintbrush to the canvas, runs your code, adjusts the layout, and THEN lets them paint. It prevents visual flickering.

Real World Example

You have a tooltip that needs to appear exactly 10px above a button. If you use `useEffect`, the tooltip might briefly render at the top of the screen (default position), and a split-second later jump to the button (visual flicker). `useLayoutEffect` calculates the position and moves the tooltip before the user ever sees it.

Common Use Cases

  • Measuring DOM elements (e.g., getting `getBoundingClientRect()`)
  • Preventing visual flickering for complex layout calculations
  • Synchronously animating elements

Interactive Example

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

export default function TooltipDemo() {
  const [show, setShow] = useState(false);
  const [topPos, setTopPos] = useState(0);
  const buttonRef = useRef(null);

  // If we used useEffect here, you might see the tooltip flash at the top 
  // of the screen for 1 frame before jumping down to the button.
  // useLayoutEffect prevents this visual flicker.
  useLayoutEffect(() => {
    if (show && buttonRef.current) {
      // Synchronously measure the DOM
      const rect = buttonRef.current.getBoundingClientRect();
      setTopPos(rect.bottom + 10); // Position exactly 10px below button
    }
  }, [show]);

  return (
    <div>
      <button ref={buttonRef} onClick={() => setShow(s => !s)}>
        Toggle Tooltip
      </button>
      
      {show && (
        <div style={{ position: 'absolute', top: topPos, background: 'black', color: 'white' }}>
          I am a tooltip!
        </div>
      )}
    </div>
  );
}

Interview Questions

basic

  • What is the difference between `useEffect` and `useLayoutEffect`?
  • Which hook is preferred by default: useEffect or useLayoutEffect?

intermediate

  • Why does `useLayoutEffect` block the visual paint?
  • What happens if you use `useLayoutEffect` in Server-Side Rendering (SSR)?

advanced

  • How do you fix the SSR warning caused by `useLayoutEffect` in Next.js?
  • In what order do multiple `useLayoutEffect` hooks fire compared to `useEffect`?

trick

  • If you fetch data from an API inside `useLayoutEffect`, does it block the browser from painting until the API request finishes?

Flash Cards

Question

What is the difference between useEffect and useLayoutEffect?

Click to reveal answer
Answer

`useEffect` is asynchronous and runs AFTER the browser paints the screen. `useLayoutEffect` is synchronous and runs BEFORE the browser paints the screen, blocking the paint.

Question

What happens if you use useLayoutEffect in SSR (like Next.js)?

Click to reveal answer
Answer

React will throw a warning. Server-Side Rendering doesn't have a DOM, so layout calculations are impossible. To fix it, you either conditionally use `useEffect` on the server, or dynamically import the component on the client only.

Question

Does fetching an API inside useLayoutEffect block the paint until the request finishes?

Click to reveal answer
Answer

No. The API fetch (e.g., fetch() or axios) is inherently asynchronous. The `useLayoutEffect` function finishes immediately after initiating the fetch, allowing the paint to happen. It does not wait for the promise to resolve.