Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 40

Understanding useEffect for Side Effects

Recommended resources

Hello! Welcome to a new module: Handling Side Effects and API Integration.

In the last lesson, we built a complete contact form that consolidated user input into a single state object. When the form was submitted, we logged that object to the console. This was a great step, but it's not a full-stack application yet. The missing piece is communication with a server. How does a React component fetch data when it first loads, or send data (like our form submission) to a backend API?

A React component's primary job is to render UI based on its props and state. Tasks like API calls, timers, or direct DOM manipulation are known as side effects because they happen "on the side" of the main rendering process. This lesson introduces the fundamental hook for managing these tasks. Your goal is to explain the purpose of the useEffect hook for handling side effects.

1. Pure Components vs. Side Effects

To understand useEffect, we first need to distinguish between a component's main job and a side effect. Ideally, a React component behaves like a pure function: for the same inputs (props and state), it always produces the same output (JSX). This predictability is a core strength of React.

However, almost any real-world application needs to interact with the "outside world"—the world outside of the component's rendering logic. These interactions are not predictable and are called side effects.

As a Laravel developer, you can think of it this way: a controller method's primary responsibility is to return a response, like a view or JSON data. However, in the process, it might perform side effects like querying a database, sending an email, or calling another service's API. React components have a similar distinction. Their main job is to return JSX, but they often need to perform side effects.

To get a solid grasp of this concept, the following article provides an excellent explanation.

The React useEffect Hook for Absolute Beginners

This article from freeCodeCamp explains the concepts of 'pure functions' and 'side effects' in the context of React, which is crucial for understanding why useEffect is necessary.

Read the first two sections: 'Why is it called useEffect?' and 'What are side effects in React?'. Focus on the distinction between a predictable, pure component and an action that interacts with the 'outside world,' like an API request.


2. Why Can't We Just Run Side Effects Directly?

You might wonder, "Why can't I just put a fetch call directly inside my component function?"

// Anti-pattern: Don't do this!
function ProductList() {
  const [products, setProducts] = useState([]);

  // This fetch call is a side effect placed directly in the render logic.
  fetch('/api/products')
    .then(res => res.json())
    .then(data => setProducts(data)); // This state update will trigger a re-render!

  return (
    <ul>
      {products.map(p => <li key={p.id}>{p.name}</li>)}
    </ul>
  );
}

The problem is that a component function re-runs (re-renders) every time its state or props change. In the code above:

  1. The component renders.
  2. The fetch call is made.
  3. The response arrives, and setProducts() is called.
  4. Calling setProducts() updates the state, which triggers a re-render.
  5. The component function runs again, making another fetch call... and so on. This creates an infinite loop, overwhelming your component and your API.

Side effects need to be separated from the rendering process to avoid these issues. We need a way to tell React: "Run this piece of code, but only after the component has rendered, and don't run it on every single render."


3. The Purpose of useEffect

This is precisely the problem the useEffect hook solves.

The purpose of useEffect is to provide a dedicated place within a function component to run side effects, decoupling them from the rendering logic.

By using useEffect, you are telling React, "After you've done all the rendering work and updated the DOM, then you can run this additional logic."

The video below gives some great, practical examples of tasks that are considered side effects and belong inside a useEffect hook.

#42 Understanding side effects in React | Side effect, Reducer and Context | A Complete React Course

This video from procademy clearly defines what side effects are and gives concrete examples that you'll encounter frequently.

Watch from the beginning until 01:47. Pay attention to the examples given—HTTP requests, browser storage, and timers—and the explanation for why they are considered side effects.

Let's formalize this with one more clear definition.

A Deep Dive into `useEffect`: Best Practices for React Developers

This article from DEV Community gives a concise definition of the hook and its role, directly addressing our learning goal.

Read the first section, 'What is the useEffect Hook?'. It neatly summarizes the hook's purpose as a replacement for older class-based lifecycle methods and as the designated place for side effects.

The basic syntax of the hook looks like this:

import { useEffect, useState } from 'react';

function MyComponent() {
  // ... state and other logic ...

  useEffect(() => {
    // Your side effect logic goes here.
    // For example: document.title = 'New Page Title';
  }); // The second argument, a dependency array, is often used here. We'll cover it next lesson.

  return <div>My Component</div>;
}

The function you pass to useEffect will be executed by React after the component renders. This ensures your side effect doesn't block the UI from being displayed and gives you a safe, predictable place to interact with the outside world.


Conclusion

In this lesson, we've established the "why" behind useEffect. It's not just another function to learn; it's a fundamental part of the React programming model that allows for clean, manageable, and performant components.

Key Takeaways:

  • A React component's main job is to render UI, and ideally, it should be a pure function.
  • Side effects are actions that interact with the "outside world," such as API calls, DOM manipulation, or timers.
  • Running side effects directly in the component body can cause performance issues and infinite loops.
  • The purpose of the useEffect hook is to provide a safe, dedicated place to run side effects after the component has rendered, separating this logic from the rendering process.

Preview of the Next Lesson:
Now that you understand why useEffect exists, we'll dive into how to use it. In the next lesson, we will focus on one of its most common uses: fetching data from an API when a component first loads. We'll learn how to use the dependency array to control exactly when our effect runs.