ReactのuseEffectでタイマー処理を扱う方法を初心者向けに解説
生徒
「Reactで一定時間ごとに処理を繰り返したいんですが、どうすればいいですか?」
先生
「そのときはJavaScriptのタイマー関数とuseEffectを組み合わせる方法が便利ですよ。」
生徒
「タイマーってアラームみたいなものですか?」
先生
「そうです。一定時間ごとに目覚まし時計が鳴るように、プログラムでも一定時間ごとに処理を実行できるんです。」
1. Reactでタイマー処理を使う基本
JavaScriptにはsetTimeoutとsetIntervalという二つのタイマー関数があります。setTimeoutは一度だけ指定した時間後に処理を実行し、setIntervalは指定した時間ごとに繰り返し処理を実行します。
ReactのuseEffectと組み合わせることで、コンポーネントが表示されたときにタイマーを設定し、画面を閉じるときにタイマーを解除する、といった安全な使い方ができます。
import React, { useEffect, useState } from "react";
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setCount((prev) => prev + 1);
}, 1000);
return () => clearInterval(timer);
}, []);
return <h1>{count}秒経過しました</h1>;
}
export default App;
2. クリーンアップ処理の大切さ
タイマー処理を扱うときに必ず覚えておきたいのが「クリーンアップ処理」です。クリーンアップとは後片付けのことです。もし画面を閉じたあとにもタイマーが動き続けると、不要な処理が走り続けてしまいパソコンに負担がかかります。
そのため、useEffectではタイマーを設定したら、終了時にclearIntervalやclearTimeoutを使って必ず解除するのがベストプラクティスです。
3. setTimeoutを使った一度だけの実行
次にsetTimeoutを使う方法を見てみましょう。これは一定時間後に一度だけ処理を実行する関数です。
import React, { useEffect, useState } from "react";
function App() {
const [message, setMessage] = useState("待機中...");
useEffect(() => {
const timer = setTimeout(() => {
setMessage("3秒が経ちました!");
}, 3000);
return () => clearTimeout(timer);
}, []);
return <h1>{message}</h1>;
}
export default App;
4. 実際の開発でよくある使い方
タイマー処理はアプリ開発でさまざまな場面で使われます。例えば次のようなケースです。
- 一定時間後に通知メッセージを自動で消す
- 数秒ごとにサーバーから新しいデータを取得する
- アニメーションのように数値をカウントアップする
これらを実現するときにも、useEffectとタイマー処理を正しく組み合わせるのが基本です。
5. 初心者が注意すべきポイント
初心者がよくつまずくのは「タイマーが二重に動いてしまう」ことです。これは、依存配列を正しく設定していない場合や、StrictModeの影響で二度実行される場合に起きます。
解決のポイントは以下です。
- 依存配列を空配列
[]にして、マウント時だけ動かす - クリーンアップ処理を必ず書く
- 二重実行が起きても問題がないような安全な処理にする
これを守れば、タイマー処理は安心して使えるようになります。
まとめ
今回の記事では、Reactにおける「useEffect」を活用したタイマー処理の基本から応用、そして注意点について詳しく解説してきました。フロントエンド開発において、ユーザー体験を向上させるために時間の制御は欠かせない要素です。JavaScriptの標準機能である「setInterval」や「setTimeout」をReactのライフサイクルの中で正しく管理することで、パフォーマンスに優れ、バグの少ないアプリケーションを構築することが可能になります。
Reactタイマー実装の要点再確認
Reactでタイマーを扱う際の最も重要なポイントは、**「コンポーネントの破棄(アンマウント)時にタイマーを止めること」**です。これを忘れると、画面が切り替わった後も裏側で処理が動き続け、メモリリークや予期せぬエラーの原因となります。useEffectの返り値として関数を定義する「クリーンアップ関数」を常に意識しましょう。
より実践的なコードサンプル:カウントダウンタイマー
ここでは、応用編として指定した秒数からカウントダウンを行い、0秒になったら停止するより実用的なコンポーネントの例を紹介します。このコードでは、残り時間を状態(state)として管理し、タイマーが0になった瞬間に自動的に停止するロジックを組み込んでいます。
import React, { useState, useEffect } from "react";
function CountdownTimer() {
const [timeLeft, setTimeLeft] = useState(10); // 10秒から開始
const [isActive, setIsActive] = useState(false);
useEffect(() => {
let timerId;
if (isActive && timeLeft > 0) {
// isActiveがtrueで、かつ残り時間がある場合のみカウントダウン
timerId = setInterval(() => {
setTimeLeft((prevTime) => prevTime - 1);
}, 1000);
} else if (timeLeft === 0) {
// 0秒になったらタイマー解除
clearInterval(timerId);
alert("時間になりました!");
}
// クリーンアップ処理:コンポーネントが消える際や、再実行前にタイマーを破棄
return () => clearInterval(timerId);
}, [isActive, timeLeft]);
return (
<div style={{ padding: "20px", textAlign: "center" }}>
<h3>残り時間: {timeLeft}秒</h3>
<button
className="btn btn-primary me-2"
onClick={() => setIsActive(true)}
disabled={isActive || timeLeft === 0}
>
タイマースタート
</button>
<button
className="btn btn-secondary"
onClick={() => {
setIsActive(false);
setTimeLeft(10);
}}
>
リセット
</button>
</div>
);
}
export default CountdownTimer;
検索エンジン最適化(SEO)の視点:なぜuseEffectとタイマーが重要か
モダンなWebサイト制作において、Reactを用いた動的なUI構築は主流となっています。検索エンジンは現在、JavaScriptの実行結果をクロールする能力を持っていますが、正しく実装されていないスクリプトはページの読み込み速度(LCPなどのコアウェブバイタル指標)に悪影響を及ぼし、検索順位を下げる要因にもなり得ます。
例えば、タイマー処理によって頻繁にDOMが更新される場合、不必要なレンダリングは避けなければなりません。依存配列を適切に設定し、メモ化技術(useCallbackなど)と組み合わせることで、Googleの評価基準である「ユーザー体験(UX)」を高めることができます。エンジニアとしては、単に動くだけでなく、効率的でクリーンなコードを書くことが、結果としてサイトのSEO評価を支えることに繋がるのです。
トラブルシューティングとベストプラクティス
開発中によく遭遇する問題として、タイマーのスピードが意図せず速くなってしまう現象があります。これは、useEffectが何度も呼び出され、古いタイマーが残ったまま新しいタイマーが生成される「タイマーの重複」が原因です。以下のチェックリストを常に確認してください。
- clearInterval / clearTimeout は漏れなく記述されているか?:useEffectのreturn内に必ず記述します。
- 依存配列(Dependency Array)は適切か?:空の配列
[]を指定すればマウント時のみ、特定の変数を入れればその変数が変わった時のみタイマーが制御されます。 - 関数型アップデートを使っているか?:
setCount(count + 1)ではなくsetCount(prev => prev + 1)と書くことで、常に最新の状態に基づいた更新が可能になります。
これらの知識を習得することで、デジタル時計の作成、スライドショーの自動再生、セッションタイムアウトの監視、リアルタイムな通知システムなど、応用範囲は無限に広がります。Reactのフック(Hooks)の中でも、useEffectは特に強力かつ奥が深いツールです。まずはシンプルな1秒ごとのカウントアップから始めて、徐々に複雑なロジックへとステップアップしていきましょう。
生徒
「先生、ありがとうございました!useEffectの中でタイマーを使うときは、後片付け(クリーンアップ)がセットだってことがよくわかりました。これを知らないと、パソコンに余計な負荷をかけちゃうんですね。」
先生
「その通りです。プログラムは『作りっぱなし』にしないことが大切なんです。特にReactのようなシングルページアプリケーション(SPA)では、画面が切り替わってもブラウザ自体はリロードされないことが多いので、古いタイマーが生き残ってしまう危険性が高いんですよ。」
生徒
「なるほど。だから return () => clearInterval(timer) という書き方が必須なんですね。あ、そういえば依存配列を [] にするのと、変数を入れるのではどう違うんですか?」
先生
「良い質問ですね!空の配列 [] なら、そのコンポーネントが最初に表示された時(マウント時)に一度だけタイマーがセットされます。もし変数を入れたら、その変数の値が変わるたびに『古いタイマーを捨てて、新しいタイマーをセットし直す』という動きになります。今回のカウントダウンの例では、タイマーの開始・停止の状態(isActive)を監視するために配列に変数を入れました。」
生徒
「使い分けが大事なんですね。最初は難しく感じたけど、実際に動くコードを見ると仕組みが見えてきました。次は30秒のカップラーメンタイマーを作ってみようと思います!」
先生
「素晴らしい挑戦ですね。もし秒数がずれるようなら、ステートの更新方法(関数型アップデート)を見直してみるといいですよ。Reactの公式ドキュメントでも推奨されている書き方なので、今のうちに癖をつけておきましょう。頑張ってくださいね!」