---
title: React Side Effects Explained with useEffect (2025 Guide)
description: 'React useEffect explained: mount vs. update vs. cleanup, dependency arrays, StrictMode double-invocation, and common bugs to avoid.'
url: https://nerdleveltech.com/react-useeffect-2025
language: en
date: '2022-10-01'
updated: '2025-09-15'
category: frontend
tags:
  - React
  - JavaScript
  - useEffect
  - Hooks
markdown_url: https://nerdleveltech.com/react-useeffect-2025.md
attribution: 'Source: NerdLevelTech — https://nerdleveltech.com/react-useeffect-2025'
terms: https://nerdleveltech.com/llms.txt
---

# React Side Effects Explained with useEffect (2025 Guide)

In React, side effects are actions that occur **outside the normal rendering process**. Examples include fetching data, updating the DOM directly, working with APIs, or syncing with browser storage. React provides the **`useEffect` hook** to handle these tasks.

---

## When Does React Run useEffect?

- **On mount** (first render).  
- **On updates** (when dependencies change).  
- **On unmount** (cleanup).  

React **never runs `useEffect`** during server-side rendering — it only runs in the browser after the component mounts. (Server Components can't use `useEffect` at all — hooks are a Client Component feature.)

---

## The Dependency Array

The second argument to `useEffect` is the **dependency array**.  

- `[]` → Run only once after mount.  
- `[value]` → Run when `value` changes.  
- Omit it → Run after **every render**.  

---

## Example: useEffect with State Dependency

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

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Count: ${count}`;
    return () => {
      document.title = "React App";
    };
  }, [count]); // effect runs whenever "count" changes

  return (
    <button onClick={() => setCount(count + 1)}>
      Increase Count ({count})
    </button>
  );
}
```

---

## StrictMode and Double-Invoked Effects

In development, wrapping your app in `<React.StrictMode>` makes React **intentionally run each effect's setup and cleanup one extra time** on mount — `setup → cleanup → setup` — specifically to surface effects that are missing proper cleanup. This has been StrictMode's behavior since React 18 and continues in React 19.

- It only happens in development builds; production builds run each effect once, as written.
- If double-invocation breaks your component (for example, duplicate API calls or subscriptions), the fix is almost always a missing or incomplete cleanup function — not disabling StrictMode.
- The counter example above will log two mount/cleanup cycles for `document.title` in development under StrictMode before settling on the correct value; that's expected, not a bug.

---

## Side Effect Examples

- **API calls** (fetching data)  
- **WebSockets** (listening to live updates)  
- **Local Storage** (persisting state)  
- **Syncing multiple states**  

---

## Best Practices (2025)

1. **Always declare dependencies** (use ESLint plugin `react-hooks/exhaustive-deps`).  
2. **Clean up effects** when possible (`return () => { ... }`).  
3. Avoid heavy computations inside `useEffect` → use **memoization** instead.  
4. For async logic, use an **async function inside** `useEffect`.  

```jsx
useEffect(() => {
  let isActive = true;

  async function fetchData() {
    const res = await fetch("/api/data");
    if (isActive) {
      // only update if still mounted
    }
  }

  fetchData();
  return () => {
    isActive = false;
  };
}, []);
```

---

## Conclusion

`useEffect` is the cornerstone of managing **side effects in React functional components**. By mastering dependency arrays, cleanup functions, and modern patterns, you’ll write React apps that are **predictable, performant, and easier to maintain**.

[^react-docs]: React Documentation. useEffect hook. https://react.dev/reference/react/useEffect
