# Understanding useEffect vs. useLayoutEffect in React
> useEffect runs after the browser paints; useLayoutEffect runs before it. When to use each, with performance notes and edge cases.
Published: 2025-03-31 · Updated: 2026-06-01
Tags: React
Canonical: https://alexmlewis.com/writing/understanding-useeffect-vs-uselayouteffect-in-react-a-comprehensive-guide
---
`useEffect` and `useLayoutEffect` both handle side effects in React function components. They differ in timing. `useEffect` runs after the browser paints; `useLayoutEffect` runs before it. That affects rendering, performance, and whether users see a flicker.

This post covers execution timing, when to use each, performance implications, and edge cases.

## Execution Timing and Rendering Behavior

### `useEffect`

- **Execution**: Runs asynchronously after the browser has painted the DOM.
- **Impact**: Non-blocking; it ensures the UI updates immediately without waiting for the side effect to complete, resulting in a smoother user experience.

### `useLayoutEffect`

- **Execution**: Executes synchronously immediately after all DOM mutations but before the browser repaints the screen.
- **Impact**: Blocking; it delays visual updates until its side effects have completed, potentially impacting user experience if misused.

## Choosing Between `useEffect` and `useLayoutEffect`

### When to Use `useEffect`
- Fetching data or other asynchronous operations.
- Managing side effects that do not require immediate DOM access.
- Most scenarios where performance and non-blocking behavior are beneficial.

### When to Use `useLayoutEffect`
- Measuring DOM elements for size, position, or layout before paint.
- Directly manipulating DOM elements to avoid flickering.
- Critical UI scenarios where immediate consistency is essential.

## Practical Examples

### Using `useEffect` for Data Fetching

```jsx
import React, { useEffect, useState } from 'react';

function FetchDataComponent() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    async function fetchData() {
      const response = await fetch('https://api.example.com/users');
      const data = await response.json();
      setUsers(data);
    }

    fetchData();
  }, []);

  return (
    <div>
      {users.length === 0 ? <p>Loading...</p> : users.map(user => <p key={user.id}>{user.name}</p>)}
    </div>
  );
}
```

### Using `useLayoutEffect` for DOM Measurement

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

function MeasureComponent() {
  const ref = useRef(null);
  const [width, setWidth] = useState(0);

  useLayoutEffect(() => {
    setWidth(ref.current.offsetWidth);
  }, []);

  return (
    <div ref={ref}>
      <p>The width of this element is: {width}px</p>
    </div>
  );
}
```

## Performance Considerations

`useLayoutEffect` has a synchronous nature that blocks the browser's paint phase. Misuse can lead to sluggishness, particularly if the operations within it are expensive or computationally heavy. It's generally advised to default to `useEffect` unless the side effect must be resolved before the browser paints.

- **Optimal Use**:
  - Limit synchronous DOM interactions to scenarios that explicitly require immediate rendering adjustments.
  - Keep DOM manipulations within `useLayoutEffect` as minimal as possible.

- **Potential Pitfalls**:
  - Excessive synchronous DOM operations leading to frame drops and reduced user experience.

## Edge Cases

### Flickering or Layout Shift

When updating DOM elements based on calculations or measurements, using `useEffect` instead of `useLayoutEffect` can cause noticeable flicker or layout shifts. In these scenarios, it's essential to switch to `useLayoutEffect`.

```jsx
// Potential flickering with useEffect
useEffect(() => {
  ref.current.style.height = `${calculateHeight()}px`;
}, []);

// Smooth rendering with useLayoutEffect
useLayoutEffect(() => {
  ref.current.style.height = `${calculateHeight()}px`;
}, []);
```

### SSR and Warning Issues

Server-Side Rendering (SSR) environments, such as Next.js, may produce warnings when using `useLayoutEffect` because there is no DOM during server rendering. The common solution is to conditionally use the hook based on the environment:

```jsx
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
```

## Best Practices

- **Always Default to `useEffect`**: Unless your side effect specifically requires immediate DOM manipulation before paint.
- **Minimize DOM Access**: Reduce expensive DOM interactions in synchronous hooks.
- **Proper Dependency Arrays**: Clearly define dependencies to avoid unnecessary re-renders or effect executions.
- **Testing and Profiling**: Use React DevTools Profiler to identify performance bottlenecks.