カテゴリ: React 更新日: 2026/02/15

ReactのuseEffectでタイマー処理を実装する方法を徹底解説!初心者でもできるReactフック入門

useEffectでタイマー処理を実装する方法
useEffectでタイマー処理を実装する方法

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

生徒

「Reactで時間が経つごとに表示を変えるタイマーって作れるんですか?」

先生

「ReactではuseEffectというフックを使うと、タイマー処理を簡単に実装できますよ。」

生徒

「フックって何ですか?そして、どうやって時間を動かすんですか?」

先生

「フックはReactで便利な仕組みのことです。useEffectを使えば、一定の間隔で処理を繰り返すこともできます。では具体的に見ていきましょう!」

1. useEffectとは?

1. useEffectとは?
1. useEffectとは?

useEffectはReactのフックのひとつで、コンポーネントが画面に表示されたときや、データが変わったときに「副作用(サイドエフェクト)」を実行するために使います。副作用とは、データを読み込んだり、ログを出力したり、タイマーを動かしたりするような「画面の描画以外の処理」のことです。 例えば、「1秒ごとに数字を増やすカウントアップタイマー」を作るとき、useEffectを利用すると簡単にできます。

2. useEffectでタイマー処理を作る基本の流れ

2. useEffectでタイマー処理を作る基本の流れ
2. useEffectでタイマー処理を作る基本の流れ

タイマー処理をReactで実装する手順は次の通りです。

  • useStateで時間やカウントを管理する
  • useEffectの中でsetIntervalを使って一定間隔ごとの処理を設定する
  • コンポーネントが消えるときにclearIntervalでタイマーを止める

これをしないと、タイマーが動き続けてメモリを使いすぎたり、二重に処理が走ったりしてしまうので注意が必要です。

3. 実際のサンプルコード

3. 実際のサンプルコード
3. 実際のサンプルコード

それでは、実際に「1秒ごとにカウントアップするタイマー」を作るプログラムを書いてみましょう。


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

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

  useEffect(() => {
    // 1秒ごとにcountを1増やす処理
    const timer = setInterval(() => {
      setCount((prevCount) => prevCount + 1);
    }, 1000);

    // コンポーネントが消えたときにタイマーを止める
    return () => clearInterval(timer);
  }, []);

  return (
    <div>
      <h1>タイマー: {count} 秒</h1>
    </div>
  );
}

export default Timer;
(画面に「タイマー: 0 秒」と表示され、1秒ごとに「1秒」「2秒」と数字が増えていきます)

4. useEffectで注意するポイント

4. useEffectで注意するポイント
4. useEffectで注意するポイント

初心者がつまずきやすいポイントとして、タイマーを止める処理を忘れるケースがあります。Reactではコンポーネントが画面から消えるときに「後片付け(クリーンアップ処理)」をする必要があります。これをuseEffectの中でreturn () => { ... }と書くことで実現できます。 もしこれをしないと、不要になったタイマーがずっと動き続け、アプリが重くなる原因になります。

5. 実用的な応用例

5. 実用的な応用例
5. 実用的な応用例

タイマー処理はゲームやストップウォッチ、残り時間のカウントダウンなどにも使われます。例えば「10秒からカウントダウンして0になったら終了メッセージを表示する」処理もuseEffectで簡単に書けます。


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

function Countdown() {
  const [time, setTime] = useState(10);

  useEffect(() => {
    if (time <= 0) return;

    const timer = setInterval(() => {
      setTime((prevTime) => prevTime - 1);
    }, 1000);

    return () => clearInterval(timer);
  }, [time]);

  return (
    <div>
      {time > 0 ? <h1>残り時間: {time} 秒</h1> : <h1>時間切れです!</h1>}
    </div>
  );
}

export default Countdown;
(画面に「残り時間: 10 秒」と表示され、1秒ごとに減っていき、0になると「時間切れです!」に変わります)

6. useEffectとsetTimeoutの違い

6. useEffectとsetTimeoutの違い
6. useEffectとsetTimeoutの違い

似たような関数にsetTimeoutがあります。これは「一度だけ時間が経ったら処理を実行する」仕組みです。対してsetIntervalは「一定間隔で繰り返す」仕組みです。 例えば「5秒後にメッセージを表示する」場合はsetTimeoutを使い、「1秒ごとに数字を増やす」場合はsetIntervalを使う、というふうに場面に応じて使い分けます。

まとめ

まとめ
まとめ

ここまで、Reactの「useEffect」フックを活用したタイマー処理の実装方法について、基礎から応用まで詳しく解説してきました。React開発において、時間の経過とともに表示を更新する機能は非常に頻繁に登場します。ストップウォッチ、カウントダウンタイマー、さらには自動スライドショーの制御など、その用途は多岐にわたります。初心者の方が最初につまずきやすいポイントは「状態管理(useState)」と「副作用(useEffect)」の連携、そして何より「クリーンアップ処理」の重要性です。

useEffectによるタイマー実装の核心

Reactのコンポーネントは、状態が変わるたびに再レンダリング(再描画)されます。しかし、setIntervalのようなブラウザのタイマー機能はReactの外側の世界で動くものです。そのため、Reactのライフサイクルに合わせて正しく制御してあげないと、予期せぬ挙動やメモリリークを引き起こしてしまいます。今回の学習で最も重要なのは、useEffectの戻り値としてclearIntervalを実行し、コンポーネントが破棄される際にタイマーを確実に止めるというルールを徹底することです。

状態更新の注意点:関数型アップデート

タイマーの中で現在のカウントを更新する場合、setCount(count + 1)とするのではなく、setCount((prev) => prev + 1)という「関数型アップデート」を使うのがベストプラクティスです。これにより、クロージャの問題を回避し、常に最新のステートに基づいた計算が可能になります。これはJavaScriptの非同期処理とReactのステート更新の仕組みを深く理解する第一歩でもあります。

実践的な活用例:複雑なタイマー制御

さらに一歩進んだ実装として、タイマーの「開始」「停止」「リセット」を切り替える機能を備えたサンプルコードを振り返ってみましょう。これらを組み合わせることで、より実用的なアプリケーションに近い形に仕上げることができます。


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

function AdvancedTimer() {
  const [seconds, setSeconds] = useState(0);
  const [isActive, setIsActive] = useState(false);

  useEffect(() => {
    let interval = null;

    if (isActive) {
      // タイマーがアクティブな時だけ動かす
      interval = setInterval(() => {
        setSeconds((prevSeconds) => prevSeconds + 1);
      }, 1000);
    } else if (!isActive && seconds !== 0) {
      // 一時停止した時の処理
      clearInterval(interval);
    }

    // クリーンアップ関数で確実に停止
    return () => clearInterval(interval);
  }, [isActive, seconds]);

  const toggle = () => setIsActive(!isActive);
  const reset = () => {
    setSeconds(0);
    setIsActive(false);
  };

  return (
    <div className="text-center p-4">
      <h3 className="mb-3">高度なタイマー</h3>
      <div className="display-4 mb-3">{seconds}秒</div>
      <div>
        <button 
          className={`btn ${isActive ? "btn-warning" : "btn-success"} me-2`} 
          onClick={toggle}
        >
          {isActive ? "一時停止" : "開始"}
        </button>
        <button className="btn btn-danger" onClick={reset}>
          リセット
        </button>
      </div>
    </div>
  );
}

export default AdvancedTimer;
(「開始」ボタンを押すとカウントが始まり、「一時停止」で止まります。「リセット」を押すと0秒に戻る、実用的なストップウォッチ風の動作になります)

このように、useEffectの依存配列(第2引数の [])を適切に設定することで、特定のステートが変化したタイミングでタイマーを再始動させたり、停止させたりといった柔軟な制御が可能になります。モダンなReact開発においては、クラスコンポーネント時代のライフサイクルメソッドよりも、フックを使った宣言的な記述が主流です。

最初は難しく感じるかもしれませんが、自分でコードを書き換えながら「依存配列に何を入れればどう動くか」を実験してみるのが上達の近道です。ぜひ、自分だけのカスタムタイマーを作って、Reactの強力な機能を体感してみてください。

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

生徒

「先生、ありがとうございました!useEffectの中でタイマーを動かす仕組みが、なんとなく掴めてきました。でも、最後に書いてあった『クリーンアップ』っていうのがやっぱり一番大事なんですね。」

先生

「その通りです!もしクリーンアップを忘れてしまうと、画面が切り替わっても裏側でタイマーがずっと走り続けて、どんどんメモリを食いつぶしちゃうんです。これを『メモリリーク』と呼ぶのですが、アプリが重くなる原因のナンバーワンと言っても過言ではありませんよ。」

生徒

「なるほど…。目に見えないからこそ、しっかり後片付けをする習慣をつけなきゃいけないんですね。あ、あと依存配列についても少し整理したいです。空の配列 [] を渡すと、どういう動きになるんでしたっけ?」

先生

「良い質問ですね。空の配列を渡すと、『このコンポーネントが最初に表示された時だけ実行する』という意味になります。最初のサンプルコードでタイマーをセットする時に使いましたね。逆に、依存配列に特定の変数を入れると、その変数が更新されるたびに useEffect が再実行されます。」

生徒

「使い分けが大事なんですね。応用例のストップウォッチでは、isActive を配列に入れていたから、ボタンを押すたびにタイマーのON/OFFが切り替えられたんだ!」

先生

「正解です!飲み込みが早いですね。Reactのフックは組み合わせ次第で無限の可能性があります。タイマーをマスターしたら、次はAPIでデータを取得して一定時間ごとに更新する『ポーリング処理』などにも挑戦してみると面白いですよ。」

生徒

「ポーリング!難しそうだけど、ニュースアプリとかで使われてそうですね。次はそれを調べてみます!Reactがますます楽しくなってきました。」

先生

「その意気です。エラーが出ても、それは成長のチャンス。一歩ずつ、楽しみながら学んでいきましょうね。」

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

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

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

ReactのuseEffectフックとは何ですか?どんな場面で使いますか?

ReactのuseEffectフックは、コンポーネントが表示されたときや更新されたときに副作用のある処理を実行するために使います。副作用とは、API通信やタイマー処理など、画面の描画以外の処理を指します。
カテゴリの一覧へ
新着記事
New1
React
Reactコンポーネントの再利用と分割を完全マスター!初心者でもわかるコンポーネント設計
New2
React
ReactでAxiosインターセプターの使い方を完全ガイド!初心者でもわかるリクエストとレスポンスの処理方法
New3
React
JSXの書き方!初心者でもわかるReactタグと属性の基本ルール解説
New4
React
ReactとDockerを使った開発環境構築の基本を徹底解説!初心者でもわかるReactとDockerの連携方法
人気記事
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でFetch APIのローディング状態を管理する方法|初心者にもわかる解説
No.5
Java&Spring記事人気No5
React
Reactのカスタムフックの作り方を完全ガイド!再利用可能なロジックを切り出す仕組み
No.6
Java&Spring記事人気No6
React
Reactでファイルアップロードを実装する方法を解説!Fetch APIで画像やPDFを送る仕組みを初心者向けに紹介
No.7
Java&Spring記事人気No7
React
create-react-appでReactプロジェクトを作成する手順を初心者向けに完全解説!
No.8
Java&Spring記事人気No8
React
ReactのuseStateとuseEffectでよくあるエラーと解決方法ガイド!初心者でもわかるReactフック