Skip to main content

Welcome to a Grasp lesson

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

Lesson 37

Mounting Actions

Recommended resources

Hello! Let's continue our exploration of the useEffect hook.

In our last lesson, we learned how the dependency array gives us precise control over when our side effects run. We saw three patterns: no array (runs on every render), an array with values (runs when those values change), and an empty array (runs only once).

Today, we're going to master that "run once" pattern. This lesson will focus entirely on using an empty dependency array [] to perform an action exactly once, right after a component is first rendered to the screen. This is one of the most common and important uses of useEffect.

By the end of this lesson, you'll understand why this pattern is essential for one-time setup tasks like fetching initial data from a server, and you'll be able to implement it correctly to avoid common bugs like infinite loops.

1. The "Mount" Effect: Running Code Once

In the previous lesson, you were introduced to the idea that providing an empty dependency array ([]) makes an effect run only once. Let's solidify that concept.

When you provide [] as the second argument to useEffect, you are essentially telling React: "This effect doesn't depend on any props or state from my component. Since its dependencies will never change, you only need to run it one time, right after the initial render."

This "run once" behavior is what we refer to when we talk about running an effect when a component mounts. Mounting is the phase in a component's life when React creates it and inserts it into the DOM for the first time.

This image provides a great visual summary. We are focusing on the "Mount" column.

React useEffect Hook Lifecycle Phases
This diagram shows how to use `useEffect` for different lifecycle phases. For running code once on mount, we use an empty dependency array `[]`.

Now, let's watch a video that walks through a code example and explains this concept in detail.

UseEffect React Hook the complete guide: Fetch data + Dependency Array + convert class to function

In this segment from Sanjeev Thiyagarajan's guide, he explains how to replicate the behavior of the classic componentDidMount lifecycle method using useEffect. He clearly demonstrates how passing an empty dependency array achieves this.

Watch the video from 17:41 to 20:27. Pay close attention to how the effect behaves when state changes after the initial render—you'll see it does not run again.

To recap the key idea from the video:

  • An effect with [] as its dependency array runs after the first render.
  • It will not run again on subsequent re-renders, regardless of what state or props change.

This makes it the perfect tool for any "setup" logic that your component needs to do only once.


2. A Core Use Case: Fetching Initial Data

The most common reason to run an effect once is to fetch data from an API when the component first loads. Let's see why the empty dependency array is crucial for this task.

Imagine you want to fetch a list of posts and display them. You might try this:

// A simplified, buggy example
function Posts() {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    fetch('https://api.example.com/posts')
      .then(res => res.json())
      .then(data => setPosts(data)); // This updates the state
  }); // 🔴 No dependency array!

  // ... render posts
}

What's the problem here?

  1. The component renders for the first time.
  2. useEffect runs because there is no dependency array.
  3. The API call is made, and eventually, setPosts(data) is called.
  4. Calling setPosts updates the component's state, which triggers a re-render.
  5. Since the component re-rendered, useEffect runs again (back to step 2).

This creates an infinite loop, bombarding the API with requests.

The solution is to tell React to only run this effect once.

// The correct way
function Posts() {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    fetch('https://api.example.com/posts')
      .then(res => res.json())
      .then(data => setPosts(data));
  }, []); // ✅ Empty dependency array

  // ... render posts
}

Now, the effect runs only after the initial render, fetches the data, updates the state once, and then stops. The infinite loop is broken.

Let's watch a detailed walkthrough of this exact scenario. It also covers the correct way to handle async/await syntax inside useEffect, which is a very practical skill.

UseEffect React Hook the complete guide: Fetch data + Dependency Array + convert class to function

Let's return to Sanjeev Thiyagarajan's guide. This section provides a fantastic, step-by-step demonstration of fetching data. He first shows how leaving out the dependency array causes an infinite loop and then shows how adding the empty array [] solves it.

Watch from 28:52 to 36:52. Note the pattern for using an async function inside the effect, as you cannot make the effect callback itself async.

The key pattern for fetching data with an async function is to define and call it from within the effect:

useEffect(() => {
  // 1. Define an async function inside the effect
  const fetchData = async () => {
    try {
      const response = await fetch('...');
      const data = await response.json();
      // 3. Update state with the fetched data
      setState(data);
    } catch (error) {
      console.error("Error fetching data: ", error);
    }
  };

  // 2. Call the function
  fetchData();
}, []); // 4. Use an empty array to run only once

This is a fundamental pattern you will use constantly when building React applications.

For a quick reference, the article "UseEffect Dependency Array: Best Practices For React" also provides a concise explanation and code example for this data-fetching pattern.

Empty Array vs No Array

This article provides a very clear summary of the difference between an empty array and no array, and includes a perfect, concise example of using an async function to fetch data within an effect that runs once.

Read the sections titled 'Empty Array vs No Array' and 'Working with Async Function in useEffect'. They serve as a great text-based summary of what you just saw in the video.


Conclusion

You have now mastered one of the most important patterns in React development. Knowing how to perform an action once on component mount is critical for creating efficient and bug-free applications.

Key Takeaways:

  • To run an effect only once when a component mounts, pass an empty dependency array ([]) as the second argument to useEffect.
  • This is the standard pattern for performing one-time setup tasks, with fetching initial data from an API being the most common use case.
  • Using an empty dependency array for data fetching is crucial to prevent infinite loops that occur when you update state inside an effect without dependency control.
  • This pattern is the modern, functional equivalent of the componentDidMount lifecycle method found in older class-based React components.

Next Up:

We've covered what happens when a component is created (mounts) and when it's updated (re-renders). But what about when it's removed from the screen? Side effects like timers or network subscriptions need to be stopped, or they can cause memory leaks. In the next lesson, we'll explore the cleanup function that you can return from useEffect to handle this.