Popular Searches
Popular Course Categories
Popular Courses

useLayoutEffect Hook

useLayoutEffect Hook

Advanced React Hooks

React useLayoutEffect Hook – Complete Notes

The useLayoutEffect Hook is a built-in React Hook used to perform layout-related operations after React updates the DOM but before the browser repaints the screen. It is especially useful when measuring an element's size or position and adjusting the UI without showing a visible layout shift.

Course Link: JustAcademy React JS Training Course

Course Demo: Register for React JS Course Demo


1. What Is the useLayoutEffect Hook?

useLayoutEffect is similar to useEffect, but it runs synchronously after React commits DOM changes and before the browser paints the updated screen. This allows developers to read layout information and make necessary adjustments before the user sees the result.

For example, if a tooltip must appear above a button when there is enough space, React may need to measure the tooltip's height before deciding its final position. The useLayoutEffect Hook can perform this measurement before the browser displays the final result.

Syntax

import { useLayoutEffect } from 'react';

useLayoutEffect(() => {
  // Read layout information or perform a layout adjustment

  return () => {
    // Optional cleanup
  };
}, [dependencies]);

Key points:

  • It runs after React updates the DOM and before the browser repaints.
  • It can measure an element's width, height, or position.
  • It can schedule state updates to correct a layout before the next paint.
  • It supports an optional cleanup function.
  • It should be used only when work must happen before the browser paints.

2. Why Do We Use useLayoutEffect?

Sometimes, a component needs to know the actual dimensions or position of an element before displaying the final UI. Using a normal effect may allow the browser to display an intermediate layout before the adjustment happens.

The useLayoutEffect Hook is useful for:

  • Measuring the height and width of DOM elements.
  • Positioning tooltips and dropdown menus.
  • Preventing visible layout shifts during positioning adjustments.
  • Calculating an element's position relative to the viewport.
  • Adjusting scroll position after a DOM update.
  • Integrating with third-party UI libraries that require synchronous layout measurements.

Important: Most effects do not need to block the browser from painting. Prefer useEffect unless the operation must happen before the user sees the updated screen.


3. How Does useLayoutEffect Work?

The general execution process is as follows:

  1. React renders the component.
  2. React updates the DOM with the rendered changes.
  3. React runs the layout effect before the browser repaints.
  4. The effect reads layout information or schedules a state update.
  5. If state changes, React performs the necessary additional rendering and DOM updates before the browser paints.
  6. The browser displays the resulting screen.

Example

import { useLayoutEffect, useRef } from 'react';

function App() {
  const boxRef = useRef(null);

  useLayoutEffect(() => {
    if (boxRef.current) {
      console.log(boxRef.current.getBoundingClientRect());
    }
  }, []);

  return (
    <div ref={boxRef}>
      Measure this element
    </div>
  );
}

export default App;

Explanation: The useRef Hook stores a reference to the DOM element. Once React has placed the element in the DOM, useLayoutEffect reads its bounding rectangle before the browser repaints.


4. Parameters of useLayoutEffect

Parameter Description
setup The function containing layout-related logic. It may return a cleanup function.
dependencies An optional array of reactive values used by the effect, including relevant props, state, and component-scope variables.

Return value: useLayoutEffect returns undefined.

Dependency Array Examples

Code Behavior
useLayoutEffect(() => {}) Runs after every commit of the component.
useLayoutEffect(() => {}, []) Runs after the initial client-side commit, subject to React development behavior.
useLayoutEffect(() => {}, [width]) Runs after the initial client-side commit and again when width changes.

React compares dependencies using Object.is. Include every reactive value used by the effect and its cleanup. Keep the dependency array's size and order constant.


5. Example: Measuring Element Height

This example uses useLayoutEffect to measure the height of an element and display it on the screen.

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

function MeasureBox() {
  const boxRef = useRef(null);
  const [height, setHeight] = useState(0);

  useLayoutEffect(() => {
    if (boxRef.current) {
      const rect = boxRef.current.getBoundingClientRect();
      setHeight(rect.height);
    }
  }, []);

  return (
    <div>
      <div
        ref={boxRef}
        style={{
          padding: '20px',
          border: '2px solid black'
        }}
      >
        This is the element being measured.
      </div>
      <p>Element height: {height}px</p>
    </div>
  );
}

export default MeasureBox;

Explanation:

  • useRef provides access to the DOM element.
  • getBoundingClientRect() returns the element's dimensions and viewport position.
  • The measured height is stored in state.
  • React renders the height value in the paragraph.

Note: This example measures the element after the initial client-side DOM commit. If the element's size changes later, you need an appropriate measurement trigger, such as a ResizeObserver, rather than relying on the empty dependency array.


6. Example: Measuring Width and Height

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

function BoxDimensions() {
  const boxRef = useRef(null);
  const [dimensions, setDimensions] = useState({
    width: 0,
    height: 0
  });

  useLayoutEffect(() => {
    if (!boxRef.current) return;

    const rect = boxRef.current.getBoundingClientRect();

    setDimensions({
      width: rect.width,
      height: rect.height
    });
  }, []);

  return (
    <div>
      <div
        ref={boxRef}
        style={{
          width: '250px',
          height: '120px',
          backgroundColor: 'lightblue'
        }}
      >
        Sample Box
      </div>
      <p>Width: {dimensions.width}px</p>
      <p>Height: {dimensions.height}px</p>
    </div>
  );
}

export default BoxDimensions;

Explanation: The Hook measures the rendered box and saves its width and height in state. These values can be used for layout decisions or displayed as information.


7. Example: useLayoutEffect with useRef

The useRef Hook and useLayoutEffect are often used together because a ref can provide access to a DOM node without causing a re-render when the ref itself changes.

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

function InputFocus() {
  const inputRef = useRef(null);
  const [message, setMessage] = useState('Enter your name');

  useLayoutEffect(() => {
    inputRef.current?.focus();
  }, []);

  return (
    <div>
      <input
        ref={inputRef}
        placeholder={message}
        onChange={() => setMessage('Keep typing')}
      />
    </div>
  );
}

export default InputFocus;

Explanation: The ref points to the input element, and the effect focuses it after the DOM commit. However, focusing an input usually does not require useLayoutEffect; use useEffect or an event handler if there is no need to perform the operation before paint.


8. Example: Positioning a Tooltip

A tooltip may need to appear above or below a button depending on the available space. Since the tooltip's actual height is known only after it has been rendered, useLayoutEffect can measure it and help determine the final position before the browser paints.

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

function Tooltip() {
  const tooltipRef = useRef(null);
  const [position, setPosition] = useState('top');

  useLayoutEffect(() => {
    if (!tooltipRef.current) return;

    const rect = tooltipRef.current.getBoundingClientRect();

    setPosition(rect.top < 0 ? 'bottom' : 'top');
  }, []);

  return (
    <div style={{ position: 'relative', margin: '60px' }}>
      <button>Hover Target</button>
      <div
        ref={tooltipRef}
        style={{
          position: 'absolute',
          top: position === 'top' ? '-40px' : '40px',
          left: 0,
          backgroundColor: 'black',
          color: 'white',
          padding: '8px'
        }}
      >
        Tooltip Message
      </div>
    </div>
  );
}

export default Tooltip;

Explanation: The tooltip is measured after it enters the DOM. The effect checks whether its top edge is outside the viewport and updates its position accordingly. This is a simplified example; a production tooltip should also account for the target element's position, viewport boundaries, scrolling, resizing, and whether the tooltip is actually visible.


9. Example: Updating Layout Before Paint

Sometimes an element initially renders with a temporary value. You can measure it and update state inside useLayoutEffect so React can apply the corrected layout before the browser paints.

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

function DynamicBox() {
  const boxRef = useRef(null);
  const [height, setHeight] = useState(100);

  useLayoutEffect(() => {
    if (!boxRef.current) return;

    const actualHeight =
      boxRef.current.getBoundingClientRect().height;

    if (actualHeight !== height) {
      setHeight(actualHeight);
    }
  }, [height]);

  return (
    <div>
      <div
        ref={boxRef}
        style={{
          height: '150px',
          backgroundColor: 'lightgreen'
        }}
      >
        Dynamic content
      </div>
      <p>Measured height: {height}px</p>
    </div>
  );
}

export default DynamicBox;

Explanation: The effect measures the element and updates the height state if the measured value differs. In this example, the displayed value converges to the measured height. In real applications, avoid unnecessary state updates and dependency patterns that cause repeated layout work.


10. useLayoutEffect vs useEffect

Both Hooks are used to run effects in function components, but their timing is different.

Feature useLayoutEffect useEffect
Execution timing After DOM changes and before browser repaint. Generally after the browser has painted the updated screen, depending on the interaction and scheduling.
Layout measurement Useful when the measurement must affect the same visible frame. Suitable when the result does not need to be applied before paint.
Visual flicker Can prevent a visible intermediate layout. May allow an intermediate frame to appear before an adjustment.
Performance Blocks repainting while its work and resulting synchronous updates are processed. Usually allows the browser to paint without waiting for effect work.
Common uses Tooltip positioning and synchronous layout corrections. Data synchronization, subscriptions, and other effects that do not require pre-paint timing.

Example Using useEffect

import { useEffect, useRef } from 'react';

function Example() {
  const boxRef = useRef(null);

  useEffect(() => {
    if (boxRef.current) {
      console.log(
        boxRef.current.getBoundingClientRect()
      );
    }
  }, []);

  return <div ref={boxRef}>Example Box</div>;
}

export default Example;

Example Using useLayoutEffect

import { useLayoutEffect, useRef } from 'react';

function Example() {
  const boxRef = useRef(null);

  useLayoutEffect(() => {
    if (boxRef.current) {
      console.log(
        boxRef.current.getBoundingClientRect()
      );
    }
  }, []);

  return <div ref={boxRef}>Example Box</div>;
}

export default Example;

Key difference: The second example performs the measurement before the browser repaints. Use it when the measurement must influence the initial visible layout; otherwise, prefer useEffect.


11. Cleanup Function in useLayoutEffect

A cleanup function is returned from the effect when necessary. React runs cleanup before the effect runs again with changed dependencies and when the component is removed.

import { useLayoutEffect, useRef } from 'react';

function ResizeExample() {
  const boxRef = useRef(null);

  useLayoutEffect(() => {
    const element = boxRef.current;
    if (!element) return;

    const observer = new ResizeObserver(entries => {
      for (const entry of entries) {
        console.log('New size:', entry.contentRect);
      }
    });

    observer.observe(element);

    return () => {
      observer.disconnect();
    };
  }, []);

  return (
    <div ref={boxRef}>
      Resize this element using CSS or responsive layout.
    </div>
  );
}

export default ResizeExample;

Explanation: A ResizeObserver observes size changes and reports updated dimensions. The cleanup disconnects the observer when it is no longer needed. If the resize information does not need to be processed before paint, using useEffect to set up the observer is generally preferable.


12. Rules of useLayoutEffect

  • Call useLayoutEffect only at the top level of a React function component or Custom Hook.
  • Do not call it inside loops, conditions, or nested functions.
  • Include every reactive dependency used by the effect.
  • Return a cleanup function when the effect creates resources that must be released.
  • Use it only when layout work must happen before the browser paints.
  • Prefer useEffect when pre-paint execution is unnecessary.
  • Remember that effects do not run during server rendering.

13. Advantages of useLayoutEffect

  • Allows DOM measurement before the browser repaints.
  • Helps correct positioning before the user sees an intermediate layout.
  • Useful for tooltips, popovers, and other components that depend on element dimensions.
  • Supports synchronous layout adjustments after DOM updates.
  • Can work with refs to read the dimensions and position of DOM elements.

14. Disadvantages and Limitations

  • It blocks the browser from repainting while its work is processed.
  • Excessive use can reduce application responsiveness.
  • It does not run during server rendering.
  • It can produce server-rendering warnings if used in components rendered on the server.
  • It is unnecessary for many ordinary side effects.
  • Repeated layout measurements and updates can cause performance problems.

15. Common Mistakes

Mistake Correct Approach
Using useLayoutEffect for every effect. Prefer useEffect unless pre-paint timing is necessary.
Forgetting dependencies. Include the reactive values used by the effect.
Measuring a missing DOM element. Check that ref.current is not null.
Updating state unnecessarily. Compare the measured value before scheduling a state update.
Forgetting cleanup. Disconnect observers and remove listeners when necessary.
Assuming the Hook runs on the server. Keep layout-dependent logic client-side or use an appropriate server-rendering strategy.
Calling the Hook conditionally. Call it at the top level of the component or Custom Hook.

16. useLayoutEffect with Server Rendering

useLayoutEffect runs only on the client because a server cannot measure the browser's layout. If a component uses server-side rendering, the layout-dependent part may need to be rendered only on the client.

Possible approaches include:

  • Use useEffect if the effect does not need to block the initial browser paint.
  • Render a suitable fallback on the server and show the layout-dependent component after client mounting.
  • Keep a component that depends on browser layout in a client-only part of the application when appropriate.
  • Consider useSyncExternalStore when the real requirement is subscribing to an external store rather than measuring layout.

Important: Do not replace useLayoutEffect with useEffect automatically if doing so would create a visible layout problem. Choose the approach based on the component's rendering requirements.


17. Interview Questions and Answers

Q1. What is useLayoutEffect in React?

Answer: It is a React Hook that runs after DOM updates and before the browser repaints, allowing synchronous layout measurement and adjustment.

Q2. What is the difference between useLayoutEffect and useEffect?

Answer: useLayoutEffect runs before repainting and blocks the paint while its work is processed. useEffect generally runs after painting and is preferred for most effects.

Q3. When should we use useLayoutEffect?

Answer: Use it when a component must measure or adjust the layout before the browser displays the updated screen, such as when positioning a tooltip.

Q4. Does useLayoutEffect run during server rendering?

Answer: No. It runs only on the client because server rendering does not have browser layout information.

Q5. Can useLayoutEffect update state?

Answer: Yes. A state update inside the Hook can cause React to render again before the browser paints.

Q6. Why can useLayoutEffect affect performance?

Answer: It blocks browser repainting while the effect and relevant synchronous updates are processed.

Q7. Can useLayoutEffect use a dependency array?

Answer: Yes. The dependency array controls when the effect runs again based on changes to reactive values.

Q8. What is the role of useRef with useLayoutEffect?

Answer: useRef can hold a reference to a DOM element, allowing the layout effect to measure its size or position.

Q9. Does useLayoutEffect require a cleanup function?

Answer: No. A cleanup function is optional and should be returned when the effect creates resources that need to be released or undone.

Q10. Should useLayoutEffect be used for API requests?

Answer: Usually not. API requests generally do not require pre-paint execution, so useEffect or a dedicated data-fetching solution is normally more appropriate.


18. Practice Exercises

  1. Create a component that measures and displays a box's height.
  2. Create a component that displays the width and height of a DOM element.
  3. Build a tooltip that chooses its position based on available viewport space.
  4. Use useRef and useLayoutEffect to measure a rendered element.
  5. Create a component that observes an element's size using ResizeObserver.
  6. Compare the visual behavior of useEffect and useLayoutEffect in a layout-measurement example.

19. Quick Revision Checklist

  • Understand the purpose of useLayoutEffect.
  • Know when it runs in relation to DOM updates and browser painting.
  • Understand its syntax and dependency array.
  • Know how to measure elements using useRef and getBoundingClientRect().
  • Understand the difference between useLayoutEffect and useEffect.
  • Know when cleanup is required.
  • Understand its performance and server-rendering limitations.
  • Use it only when pre-paint layout work is necessary.

20. Official React Documentation


21. React JS Training Resources

Learn React Hooks, component behavior, and practical application development through these resources:

Conclusion

The useLayoutEffect Hook is useful when a React component needs to read or adjust layout information before the browser repaints the screen. It is commonly used for measuring DOM elements, positioning tooltips, and preventing visible layout shifts. Since it can block repainting and does not run on the server, use it selectively and prefer useEffect whenever pre-paint timing is not required.

whatsapp