Learnitweb

useLayoutEffect

useLayoutEffect is a version of useEffect that fires before the browser repaints the screen. useLayoutEffect can hurt performance. Prefer useEffect when possible.

References

useLayoutEffect(setup, dependencies?)

Call useLayoutEffect to perform the layout measurements before the browser repaints the screen.

Parameters

  • setup: The function with your Effect’s logic. Your setup function may also optionally return a cleanup function. Before your component is added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. Before your component is removed from the DOM, React will run your cleanup function.
  • optional dependencies: The list of all reactive values referenced inside of the setup code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is configured for React, it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like [dep1, dep2, dep3]. React will compare each dependency with its previous value using the Object.is comparison. If you omit this argument, your Effect will re-run after every re-render of the component.

Returns

useLayoutEffect returns undefined.

Caveats 

  • useLayoutEffect is a Hook, so you can only call it at the top level of your component or your own Hooks. You can’t call it inside loops or conditions. If you need that, extract a component and move the Effect there.
  • When Strict Mode is on, React will run one extra development-only setup+cleanup cycle before the first real setup. This is a stress-test that ensures that your cleanup logic “mirrors” your setup logic and that it stops or undoes whatever the setup is doing. If this causes a problem, implement the cleanup function.
  • If some of your dependencies are objects or functions defined inside the component, there is a risk that they will cause the Effect to re-run more often than needed. To fix this, remove unnecessary object and function dependencies. You can also extract state updates and non-reactive logic outside of your Effect.
  • Effects only run on the client. They don’t run during server rendering.
  • The code inside useLayoutEffect and all state updates scheduled from it block the browser from repainting the screen. When used excessively, this makes your app slow. When possible, prefer useEffect.
  • If you trigger a state update inside useLayoutEffect, React will execute all remaining Effects immediately including useEffect.

Use Cases for useLayoutEffect

Here are common and practical scenarios where useLayoutEffect is the right tool:

1. Measuring DOM Elements (e.g. width, height, position)

If you need accurate layout measurements before rendering dependent content (like tooltips or animations), use useLayoutEffect.

const boxRef = useRef();

useLayoutEffect(() => {
  const { width, height } = boxRef.current.getBoundingClientRect();
  console.log('Box size:', width, height);
}, []);

Guarantees you’re reading the actual DOM size before it’s visible to the user.

2. Synchronous DOM Manipulations

If you need to immediately update the DOM (e.g., scroll position, focus), and don’t want visible flickers:

const inputRef = useRef();

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

Unlike useEffect, this avoids a “flash” where the input isn’t focused until after the paint.

3. Preventing Flicker in Animations

When triggering animations or layout changes, use useLayoutEffect to apply styles before paint, so the transition is smooth.

useLayoutEffect(() => {
  elementRef.current.style.opacity = 1; // No flicker
}, []);

If this were in useEffect, users might see a brief state with opacity: 0.

4. Reading & Writing Layout in Sequence

If you’re calculating layout and then updating it based on measurement:

useLayoutEffect(() => {
  const el = ref.current;
  const height = el.getBoundingClientRect().height;

  // Set a margin dynamically based on height
  el.style.marginTop = `${height}px`;
}, []);

This ensures the DOM read/write happens before paint, avoiding layout thrashing or visual glitches.

5. Custom Scroll Handling

For sticky headers, auto-scrolling, or scroll-based effects, useLayoutEffect ensures changes are in place before the browser paints.

useLayoutEffect(() => {
  window.scrollTo(0, 0); // Scroll to top immediately
}, []);

When NOT to Use useLayoutEffect

  • For side effects not related to layout or DOM, use useEffect instead.
  • Overuse of useLayoutEffect can block rendering and cause performance issues, especially on slower devices.
  • Avoid async operations inside it—it blocks paint until it’s done.

Key Difference from useEffect:

  • useEffect – Runs after paint
  • useLayoutEffect – Runs before paint, after DOM updates