Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. React Dictionary
  3. Lifecycle

Lifecycle

Since: React 16.8(2019)

In React, the lifecycle refers to the sequence of stages a component goes through: "mounting" when it first appears on screen, "updating" in response to data changes, and "unmounting" when it disappears. In function components, the useEffect hook is used to hook into each of these stages.

Main Lifecycle Phases

PhaseOverview
MountThe stage when the component is first added to the DOM. This is where initial data fetching or connecting to external services takes place.
UpdateThe stage when the component re-renders due to changes in state or props. Side-effect logic can be run in response to those changes.
UnmountThe stage when the component is removed from the DOM. Cleanup tasks such as clearing timers and removing event listeners are performed here.

useEffect Syntax

import { useEffect } from 'react';

// Runs after every render (no dependency array)
useEffect(() => {
  // side-effect logic
});

// Runs only on mount (empty dependency array)
useEffect(() => {
  // side-effect logic
  return () => {
    // cleanup logic (runs on unmount)
  };
}, []);

// Runs only when specified values change (dependency array provided)
useEffect(() => {
  // side-effect logic
  return () => {
    // cleanup logic
  };
}, [dependentValue]);

useEffect Second Argument (Dependency Array) Behavior

Dependency ArrayWhen It Runs
Omitted (no argument)Runs after every render. Because this affects performance, specifying a dependency array is generally preferred.
[] (empty array)Runs once when the component mounts. Useful for initial data fetching.
[value1, value2]Runs when any value in the array changes compared to the previous render. Use this when you want to react to specific state or props changes.

Sample Code

An example that performs processing at the mount, update, and unmount stages of a component.

import { useState, useEffect } from 'react';

function Timer() {
  const [seconds, setSeconds] = useState(0);
  const [isRunning, setIsRunning] = useState(false);

  // Runs every time isRunning changes
  useEffect(() => {
    // Do not run the timer when isRunning is false
    if (!isRunning) {
      return;
    }

    // Set an interval that increments seconds by 1 every second
    const intervalId = setInterval(() => {
      setSeconds((prev) => prev + 1);
    }, 1000);

    // Cleanup function: called before the next effect runs or on unmount
    // Clears the interval to prevent memory leaks
    return () => {
      clearInterval(intervalId);
    };
  }, [isRunning]); // Specify isRunning in the dependency array

  return (
    <div>
      <p>Elapsed time: {seconds} seconds</p>
      <button onClick={() => setIsRunning(true)}>Start</button>
      <button onClick={() => setIsRunning(false)}>Stop</button>
      <button onClick={() => { setIsRunning(false); setSeconds(0); }}>Reset</button>
    </div>
  );
}

export default Timer;

Sample Code: Data Fetching

An example that fetches data from an external API on mount.

import { useState, useEffect } from 'react';

function UserList() {
  // Manage the user list, loading flag, and error information separately in state
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  // Use an empty dependency array to fetch data only on mount
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then((response) => {
        // Throw an error if the response is not successful
        if (!response.ok) {
          throw new Error('Failed to fetch data.');
        }
        return response.json();
      })
      .then((data) => {
        // Store the fetched data in state
        setUsers(data);
        setLoading(false);
      })
      .catch((err) => {
        // Store the error information in state and end loading
        setError(err.message);
        setLoading(false);
      });
  }, []); // Empty array: runs only once on mount

  if (loading) {
    return <p>Loading...</p>;
  }

  if (error) {
    return <p>Error: {error}</p>;
  }

  return (
    <ul>
      {users.map((user) => (
        // Always specify a unique key for list items
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

export default UserList;

Overview

Lifecycle control in function components is consolidated into the single useEffect hook. The roles of the three methods from the class component era — componentDidMount, componentDidUpdate, and componentWillUnmount — are expressed by varying how the dependency array is specified.

The cleanup function (the return () => { ... } part) is called just before the next effect runs and when the component unmounts. For resources that require explicit release — such as timers, event listeners, and WebSocket connections — cleanup must be performed in the cleanup function.

Multiple useEffect calls can be written in a single component. Splitting them by concern makes the code easier to follow.

Related pages: useState / Component

Common Mistakes

Forgetting to add a value to the dependency array and referencing a stale value

If a variable is left out of useEffect's dependency array, the value captured inside the effect becomes stale (the closure trap). The ESLint rule react-hooks/exhaustive-deps can detect this automatically.

stale_ng.jsx
import { useState, useEffect } from 'react';

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

  useEffect(function() {
    const id = setInterval(function() {
      // count is not in the dependency array, so it always references the initial value 0
      console.log(name + ' count:', count);
    }, 1000);
    return function() { clearInterval(id); };
  }, []); // count is missing

  return <button onClick={function() { setCount(function(c) { return c + 1; }); }}>{count}</button>;
}

function App() {
  return <Counter name="Kiryu Kazuma" />;
}

Fixed:

stale_ok.jsx
useEffect(function() {
  const id = setInterval(function() {
    console.log(name + ' count:', count);
  }, 1000);
  return function() { clearInterval(id); };
}, [count, name]); // List all values that are used

Forgetting to return a cleanup function and causing a memory leak

If a cleanup function is not returned from a useEffect that registers a timer or event listener, the resource continues to exist after the component unmounts, causing a memory leak. Always release registered resources in the cleanup function.

cleanup_ng.jsx
import { useEffect } from 'react';

function StatusMonitor({ userId }) {
  useEffect(function() {
    const intervalId = setInterval(function() {
      console.log('Checking status for ' + userId);
    }, 5000);
    // No cleanup returned, so the timer keeps running after unmount
  }, [userId]);

  return <p>Monitoring: {userId}</p>;
}

Fixed:

cleanup_ok.jsx
import { useEffect } from 'react';

function StatusMonitor({ userId }) {
  useEffect(function() {
    const intervalId = setInterval(function() {
      console.log('Checking status for ' + userId);
    }, 5000);
    // Clear the timer in the cleanup function
    return function() { clearInterval(intervalId); };
  }, [userId]);

  return <p>Monitoring: {userId}</p>;
}

function App() {
  return <StatusMonitor userId="Majima Goro" />;
}

Using an empty dependency array to run only on mount, but getting a state update error when async processing completes after unmount

When fetch is executed on mount with a [] dependency array, if the component unmounts before fetch completes, setState will be called afterward and produce an error. Logic to cancel the fetch in the cleanup function is required.

fetch_ng.jsx
import { useState, useEffect } from 'react';

function Profile({ userId }) {
  const [data, setData] = useState(null);

  useEffect(function() {
    fetch('/api/users/' + userId)
      .then(function(res) { return res.json(); })
      .then(function(json) {
        // Produces a warning if executed after unmount
        setData(json);
      });
  }, []);

  return <p>{data ? data.name : 'Loading...'}</p>;
}

Fixed:

fetch_ok.jsx
import { useState, useEffect } from 'react';

function Profile({ userId }) {
  const [data, setData] = useState(null);

  useEffect(function() {
    let cancelled = false;

    fetch('/api/users/' + userId)
      .then(function(res) { return res.json(); })
      .then(function(json) {
        if (!cancelled) { setData(json); }
      });

    return function() { cancelled = true; };
  }, [userId]);

  return <p>{data ? data.name : 'Loading...'}</p>;
}

function App() {
  return <Profile userId="spring_kasuga" />;
}

If you find any errors or copyright issues, please .