カテゴリ: React 更新日: 2026/01/16

ReactのuseEffectでメモリリークを防ぐ方法!初心者でもわかるクリーンアップ関数の使い方

useEffectでメモリリークを防ぐ方法(クリーンアップ関数)
useEffectでメモリリークを防ぐ方法(クリーンアップ関数)

先生と生徒の会話形式で理解しよう

生徒

「先生、Reactのプログラムを作っていたら、エラーで『メモリリーク』って出たんですけど、これはなんですか?」

先生

「メモリリークというのは、もう使わないはずのメモリ(パソコンの作業スペース)が解放されずに残り続けてしまうことです。放っておくとパソコンが重くなったり、アプリが動かなくなったりするんです。」

生徒

「Reactでもそんなことが起きるんですか?」

先生

「はい。特にuseEffectを使って非同期処理やタイマーを設定したときに、クリーンアップを忘れるとメモリリークの原因になります。」

生徒

「じゃあどうやって防げばいいんですか?」

先生

「それにはクリーンアップ関数を使います。具体的にコードを見ていきましょう。」

1. メモリリークとは何か

1. メモリリークとは何か
1. メモリリークとは何か

メモリリークとは、アプリが使わなくなったデータや処理を解放しないで残してしまうことです。たとえるなら、使い終わったペットボトルを捨てずに机に溜め続けているようなものです。最初は気にならなくても、だんだん机がいっぱいになって仕事ができなくなります。パソコンも同じで、メモリリークが溜まると動作が重くなり、最悪の場合アプリが落ちることもあります。

2. useEffectでメモリリークが起きる原因

2. useEffectでメモリリークが起きる原因
2. useEffectでメモリリークが起きる原因

useEffectは、Reactで副作用(データの取得やタイマー処理など)を扱うときに使うフックです。しかし、コンポーネントが画面から消えたあとでも処理が残り続けると、メモリが解放されずにリークが起きます。

  • API通信が終わる前に画面が切り替わる
  • タイマーやイベントリスナーを設定したまま放置する
  • コンポーネントがアンマウント(削除)されたのに処理が残っている

これらが原因で「Warning: Can't perform a React state update on an unmounted component」といったエラーが出ることがあります。

3. クリーンアップ関数とは?

3. クリーンアップ関数とは?
3. クリーンアップ関数とは?

クリーンアップ関数とは、コンポーネントが画面から消えるときに呼ばれる「お片付け用の関数」です。例えば学校の授業が終わったら黒板を消すように、使い終わった処理をきれいに消す役割があります。ReactのuseEffectでは、関数の中からreturn () => { ... }の形で書くことでクリーンアップを行います。

4. setIntervalをクリーンアップする例

4. setIntervalをクリーンアップする例
4. setIntervalをクリーンアップする例

よくある例が、setIntervalで時間ごとに処理を実行するケースです。これをそのままにすると、コンポーネントが消えてもタイマーが動き続けてメモリリークになります。


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

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

  useEffect(() => {
    const id = setInterval(() => {
      setCount((prev) => prev + 1);
    }, 1000);

    return () => {
      clearInterval(id);
    };
  }, []);

  return (
    <div>
      <h1>カウント: {count}</h1>
    </div>
  );
}

export default Timer;
(画面に「カウント: 0」と表示され、1秒ごとに数字が増えていきます。画面を切り替えるとタイマーが止まり、メモリリークを防げます)

5. API通信でのクリーンアップ例

5. API通信でのクリーンアップ例
5. API通信でのクリーンアップ例

API通信でも同じ問題が起きます。例えばコンポーネントが消えたあとにsetStateを呼ぶとエラーになります。このときは、フラグを使って「もう処理しない」と判断させます。


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

function FetchData() {
  const [data, setData] = useState(null);

  useEffect(() => {
    let isMounted = true;

    fetch("https://jsonplaceholder.typicode.com/todos/1")
      .then((res) => res.json())
      .then((result) => {
        if (isMounted) {
          setData(result);
        }
      });

    return () => {
      isMounted = false;
    };
  }, []);

  return (
    <div>
      <h1>{data ? data.title : "読み込み中..."}</h1>
    </div>
  );
}

export default FetchData;
(最初は「読み込み中...」と表示され、データ取得が成功するとタイトルが表示されます。画面を切り替えるとクリーンアップが走り、安全に処理が終了します)

6. イベントリスナーのクリーンアップ

6. イベントリスナーのクリーンアップ
6. イベントリスナーのクリーンアップ

もうひとつよくあるのが、ブラウザのイベントリスナーです。例えばスクロールやリサイズイベントを設定すると、消すのを忘れがちです。これもremoveEventListenerでクリーンアップしましょう。


useEffect(() => {
  const handleResize = () => {
    console.log("画面サイズが変わりました");
  };
  window.addEventListener("resize", handleResize);

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

こうしておけば、コンポーネントが消えたときに自動でリスナーが解除され、メモリリークを防げます。

7. クリーンアップを習慣にしよう

7. クリーンアップを習慣にしよう
7. クリーンアップを習慣にしよう

クリーンアップ関数は、Reactで安全にアプリを作るための基本です。最初は「お片付けを忘れないようにする」というイメージで大丈夫です。処理を追加したら「消す処理も書く」とセットで覚えると安心です。

特に初心者がつまずきやすいのが「エラーは出ていないけど、裏で処理が動き続けている」ケースです。こうした問題は一見気づきにくいですが、クリーンアップをきちんと書いておけば防げます。

まとめ

まとめ
まとめ

useEffectとメモリリークの関係を振り返る

今回の記事では、ReactのuseEffectを使う際に起こりやすいメモリリークの問題と、 それを防ぐためのクリーンアップ関数の使い方について詳しく学んできました。 Reactは便利なライブラリですが、非同期処理やタイマー、イベントリスナーを扱う場面では、 「使い終わった処理をきちんと片付ける」という意識を持たないと、 知らないうちにメモリリークが発生してしまいます。

メモリリークとは、もう必要のない処理やデータがメモリ上に残り続けてしまう状態です。 小さなサンプルでは気づきにくいですが、画面遷移が多いアプリや、 長時間動き続けるWebアプリでは、動作が重くなったり、 警告メッセージが表示されたりと、さまざまな不具合の原因になります。 そのため、ReactでuseEffectを書くときは、 「この処理はいつ始まり、いつ終わるのか」を常に考えることが重要です。

クリーンアップ関数の役割と考え方

クリーンアップ関数は、コンポーネントが画面から消えるタイミングで実行される、 いわば「後片付け専用の処理」です。 useEffectの中でreturn () => { ... }と書くことで定義でき、 タイマーの停止、イベントリスナーの解除、フラグの切り替えなどをまとめて行えます。 初心者の方は、「何かを始めたら、必ず終わらせる処理を書く」というルールを ひとつの習慣として覚えておくと安心です。

特に、setIntervaladdEventListener、 API通信後のsetStateなどは、 クリーンアップを忘れるとメモリリークにつながりやすい代表例です。 記事内で紹介したように、clearIntervalremoveEventListenerを正しく呼び出すだけで、 多くのトラブルを未然に防ぐことができます。

シンプルな復習用サンプル

ここで、今回学んだ内容をまとめて確認できるシンプルな例を見てみましょう。 タイマーを使い、クリーンアップ関数で確実に停止することで、 メモリリークを防ぐ基本的な形になっています。


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

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

  useEffect(() => {
    const timerId = setInterval(() => {
      setCount((prev) => prev + 1);
    }, 1000);

    return () => {
      clearInterval(timerId);
    };
  }, []);

  return (
    <div>
      <p>カウント: {count}</p>
    </div>
  );
}

export default CleanupSummary;
(画面にカウントが表示され、1秒ごとに増えます。画面を離れるとタイマーが停止し、安全に終了します)

このように、クリーンアップ関数を正しく書いておけば、 コンポーネントがアンマウントされたあとに処理が残ることはありません。 見た目は小さな違いでも、実務ではアプリの安定性に大きく影響します。 Reactで安全に非同期処理を扱うための基礎として、 クリーンアップの考え方は必ず身につけておきたいポイントです。

先生と生徒の振り返り会話

生徒

「useEffectって便利ですけど、何も考えずに使うとメモリリークの原因になるんですね。 クリーンアップ関数の大切さがよく分かりました。」

先生

「そうですね。Reactでは処理を書くことよりも、 処理を終わらせることが大事な場面も多いんです。 特に非同期処理やイベントは注意が必要ですね。」

生徒

「これからはuseEffectを書くときに、 ちゃんとreturnでクリーンアップを書いているか確認するようにします。」

先生

「それができれば十分です。 クリーンアップを習慣にすれば、Reactのエラーや警告も減り、 安定したアプリが作れるようになりますよ。」

今回のまとめとして、ReactのuseEffectとクリーンアップ関数は、 メモリリークを防ぎ、安心してアプリを動かすための基本中の基本です。 小さなサンプルからでも意識して取り入れることで、 実務レベルでも通用するReactの書き方が自然と身についていきます。

この記事を読んだ人からの質問

この記事を読んだ人からの質問
この記事を読んだ人からの質問

プログラミング初心者からのよくある疑問/質問を解決します

Reactでメモリリークとはどんな現象のことですか?

Reactにおけるメモリリークとは、本来不要になったデータや処理が解放されず残り続けてしまう現象のことです。たとえば、タイマー処理や非同期処理がコンポーネント削除後も残るとメモリが無駄に使われ、アプリの動作が重くなる原因になります。
カテゴリの一覧へ
新着記事
New1
React
ReactのuseEffectでAPIを呼び出す正しい方法を解説!初心者でもできる非同期処理の基本
New2
React
ReactのuseEffectでイベントリスナーを登録・解除する方法を徹底解説!初心者向けReactフック入門
New3
React
Reactコンポーネントの再利用と分割を完全マスター!初心者でもわかるコンポーネント設計
New4
React
ReactでAxiosインターセプターの使い方を完全ガイド!初心者でもわかるリクエストとレスポンスの処理方法
人気記事
No.1
Java&Spring記事人気No1
React
ReactでonChangeイベントを使ってフォーム入力値を管理する方法を初心者向けに解説
No.2
Java&Spring記事人気No2
React
ReactとTypeScriptの環境構築をやさしく解説!Viteとtsconfigの設定も丁寧に紹介
No.3
Java&Spring記事人気No3
React
Reactのイベントハンドリングのアンチパターンまとめ!初心者でもわかる注意点
No.4
Java&Spring記事人気No4
React
Reactのカスタムフックの作り方を完全ガイド!再利用可能なロジックを切り出す仕組み
No.5
Java&Spring記事人気No5
React
ReactでFetch APIのローディング状態を管理する方法|初心者にもわかる解説
No.6
Java&Spring記事人気No6
React
Reactでファイルアップロードを実装する方法を解説!Fetch APIで画像やPDFを送る仕組みを初心者向けに紹介
No.7
Java&Spring記事人気No7
React
ViteでReact開発環境を構築する手順を完全ガイド!初心者でもできるReactの環境構築
No.8
Java&Spring記事人気No8
React
ReactのuseStateとuseEffectでよくあるエラーと解決方法ガイド!初心者でもわかるReactフック