Mastering Side Effects: The useEffect Hook in React

Connect your components to the outside world for data fetching, subscriptions, and much more.

⚛️ ↔️ 🌐

Welcome! Our components are great for UI, but how do they interact with the outside world, like an API?

/* How to connect to the outside world? */

What is a Side Effect?

A side effect is any operation in your component that affects something outside of itself. Common examples include fetching data from an API, setting up a timer with `setInterval`, or manually changing the DOM. The `useEffect` hook provides a way to handle these operations cleanly within functional components.

The Dependency Array: Controlling the Effect

The dependency array is the second argument to `useEffect`, and it controls *when* your effect runs.

  • `[]` (empty array): The effect runs only once, after the initial render. Perfect for initial data fetching.
  • `[prop, state]` (with values): The effect runs once on mount, and then again any time one of the dependency values changes.
  • No array: The effect runs after every single render. Use this with caution as it can cause performance issues.

The Cleanup Function: Preventing Memory Leaks

Some side effects need to be cleaned up to prevent memory leaks, like subscriptions or timers. You can do this by returning a function from your effect. React will execute this cleanup function when the component unmounts, or before the effect runs again.

The Result: Full Lifecycle Management

By mastering `useEffect`, you can manage the entire lifecycle of a component's side effects. This allows you to build complex, stateful components that can interact with the browser and external services reliably, creating a seamless user experience.

Practice Zone


Interactive Test 1: Match the Behavior

Match the `useEffect` dependency array to its execution behavior.

Arrastra en el orden correspondiente.


Arrastra las opciones:

useEffect(() => { ... })
useEffect(() => { ... }, [])
useEffect(() => { ... }, [id])

Completa el código:

Runs once on mount______
Runs when 'id' changes______
Runs on every render______
Unlock with Premium

Interactive Test 2: Complete the Code

Rellena los huecos en cada casilla.

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  (() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data));
  }, []);

  return <div>{user?.name}</div>;
}
Unlock with Premium

Practice Example: Code Editor

Fetch data from the API endpoint `https://jsonplaceholder.typicode.com/todos/1` when the component mounts and display the todo's title.

Enunciado:

* Escribe el código a continuación. Los caracteres correctos se mostrarán en verde y los incorrectos en rojo.

function TodoFetcher() { const [todo, setTodo] = useState(null); useEffect(() => { fetch('https://jsonplaceholder.typicode.com/todos/1') .then(response => response.json()) .then(data => setTodo(data)); }, []); if (!todo) return <p>Loading...</p>; return <h1>{todo.title}</h1>; }

Unlock with Premium

Knowledge Check

What does an empty dependency array ([]) in useEffect signify?


Unlock with Premium

`useEffect` in Action

`useEffect` is the bridge between React's declarative world and the imperative world of browser APIs, network requests, and third-party libraries. Here are some practical examples.


1. Fetching Data on Load

The most frequent use case for `useEffect`. An empty dependency array (`[]`) ensures the fetch only happens once when the component mounts, preventing unnecessary network requests on re-renders.

const [user, setUser] = useState(null);

useEffect(() => {
  fetch('/api/user/1')
    .then(res => res.json())
    .then(data => setUser(data));
}, []); // Runs only once!

Result:

{ name: 'John Doe' }

2. Responding to Prop Changes

When you pass a value to the dependency array, the effect will re-run whenever that value changes. This is perfect for fetching new data when a user navigates to a different item.

function UserProfile({ userId }) {
  useEffect(() => {
    // Fetches data for the new userId
    fetch(`/api/users/${userId}`);
  }, [userId]); // Re-runs when userId changes
}
Fetches user 2...
Fetches user 3...

3. Cleaning Up Subscriptions

If your effect subscribes to something (like a WebSocket or a browser event), you must clean it up to avoid memory leaks. The returned function from `useEffect` is the perfect place for this logic.

useEffect(() => {
  const handleResize = () => { /*...*/ };
  window.addEventListener('resize', handleResize);

  return () => {
    window.removeEventListener('resize', handleResize);
  };
}, []);
Listener Removed

Practical Takeaway: Think of `useEffect` as a way to synchronize your React component with an external system. Use the dependency array to control *when* that synchronization happens.

`useEffect` Glossary

Side Effect
Any operation that interacts with the world outside of a component's render cycle, such as API calls, subscriptions, timers, or direct DOM manipulation.
useEffect Hook
A React Hook that lets you perform side effects in functional components. It runs after the component has rendered to the screen.
Dependency Array
The optional second argument to `useEffect`. It's an array of values that the effect depends on. The effect will only re-run if one of these values has changed between renders.
Cleanup Function
A function that can be returned from an effect. React runs the cleanup function before the component unmounts and before re-running the effect due to dependency changes.
Mount / Unmount
"Mounting" is the process of React rendering a component to the DOM for the first time. "Unmounting" is when the component is removed from the DOM.