こんにちは!Reactの学習、毎日お疲れ様です。
画面に文字やボタンを表示させられるようになって、「よし、動いたぞ!」と楽しくなってきた頃に、必ずと言っていいほど私たちの前に立ちはだかる大きな壁があります。
そう、それが`useEffect`(ユーズエフェクト)です。
「なんか画面の再描画とは別に動くらしいけど、いつの間にか無限ループしてブラウザがフリーズする……」
「クリーンアップ関数? お掃除って一体何をすればいいの?」
初心者の方とお話ししていると、この`useEffect`の挙動で悩まれている声を本当にたくさん聞きます。大丈夫です、安心してください。最初は誰もが通る「Reactの洗礼」のようなものですから、今日ここで一緒にスッキリとモヤモヤを解消していきましょう!
今回は、`useEffect`の数ある使い道の中でも、一番本質的で、かつ実務でも絶対に避けて通れない「外部システムとの同期」というテーマに絞って、身近な例えを交えながら優しく紐解いていきますね。
—
1. 「Reactの世界」と「外の世界」は、言葉が通じない別世界?
まず、私たちが普段書いているReactのコードの世界を想像してみてください。ここは、状態(State)が変わるたびに自動で画面を綺麗にお化粧直ししてくれる、とってもスマートで居心地の良いお城のような場所です。
一方で、Reactの管理が及ばない「外の世界」が存在します。
例えば、こんなものたちです。
- ブラウザ標準の機能(ウィンドウの大きさ、タイマー、スクロール位置など)
- 昔ながらのJavaScriptライブラリ(チャートを描くChart.jsや、地図を表示するLeafletなど)
- 外部のサーバーとリアルタイムでやり取りする仕組み(WebSocketなど)
これらは、Reactのお城の外にある「大自然や別の街」のようなもの。Reactのルールだけでは、外の世界の「今、ウィンドウのサイズが変わったよ!」という変化を直接キャッチすることができません。
だからこそ、「お城(React)の住人と、外の世界の住人が、お互いの情報をすれ違いなく共有する(=同期する)」ための通訳さんが必要になります。
その通訳さんこそが、まさに`useEffect`なんです。
—
2. 例え話で納得!「お店の自動ドア」とお買い物の流れ
「外部システムとの同期」と言われても、なんだか硬い言葉ですよね。
ここでは、身近にある「お店の自動ドア」を例に考えてみましょう。
あなたがあるお店の店員さんだとします。
- お客さんが近づいたら(=外の世界の変化)、自動ドアが開く(=React側の状態を変化させる)。
- お店が閉店して営業終了したら(=コンポーネントが画面から消える)、自動ドアの電源を切る(=後始末をする)。
もし、この「後始末」を忘れて帰ってしまったらどうなるでしょうか? 夜中にお客さんが誰もいないのにドアが開きっぱなしになり、電気代が無駄にかかったり、不具合の原因になりますよね。
Reactの`useEffect`もこれと全く同じです。
1. 外の世界とつながる(同期の開始)
2. 用事が済んだら、きれいにお片付けする(クリーンアップ)
このセットの動きをマスターするのが、`useEffect`を使いこなす一番の近道なのです。
—
3. 実践!ウィンドウの幅とReactを同期させてみよう
百聞は一見に如かず。実際にコードを見てみましょう!
今回は、「今、ブラウザの横幅が何ピクセルあるか」という外の世界の情報を、ReactのStateにリアルタイムで同期させるコンポーネントを作ります。
以下のコードをそのままコピーして、あなたのエディタやCodeSandboxなどで試してみてください。
import React, { useState, useEffect } from ‘react’;
function WindowWidthChecker() {
// 1. 現在のウィンドウの幅を保持するReactの状態(State)を用意
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
useEffect(() => {
// — 【ここから:同期のセットアップ】 —
// 外の世界(ブラウザ)の「ウィンドウサイズが変わったよ」というイベントを監視する関数
const handleResize = () => {
// 外の世界の変化を、Reactの世界の状態(State)に教えてあげる
setWindowWidth(window.innerWidth);
};
// ブラウザの「リサイズイベント」に、私たちの関数を登録する
window.addEventListener(‘resize’, handleResize);
console.log(‘【お仕事開始】イベントリスナーを登録しました!’);
// — 【ここから:クリーンアップ(お片付け)】 —
// このコンポーネントが画面から消えるとき、または再実行される直前に呼ばれるお掃除関数
return () => {
// 登録しっぱなしにしておくとメモリの無駄遣い(バグの原因)になるので、ここで綺麗に剥がす!
window.removeEventListener(‘resize’, handleResize);
console.log(‘【お片付け】イベントリスナーを解除しました!’);
};
}, [/ 依存配列 /]);
// 空の配列「[]」を渡すことで、「このコンポーネントが最初に画面に出たときだけ、外の世界と繋がってね」と指示しています。
return (
ウィンドウ幅の同期チェッカー
現在のブラウザの横幅は…
ブラウザの端っこをマウスで引っ張って、サイズを変えてみてください!数字がリアルタイムに変わりますよ。
);
}
export default WindowWidthChecker;
コードのここがポイント!
1. `window.addEventListener` で外の世界と握手
`useEffect`の中身は、コンポーネントが画面に表示された(マウントされた)瞬間に1度だけ実行されます。ここでブラウザという「外の世界」と繋がっています。
2. 「お片付け(クリーンアップ)」を絶対に忘れない
`return () => { … }` の部分ですね。ここが初心者の頃は忘れがちなのですが、「外の世界と繋がったら、用事が済んだときに元通りに戻す(イベントを削除する)」というお片付けは、エンジニアとしてのマナーであり、メモリリーク(動作が重くなるバグ)を防ぐための非常に重要な防衛策です。
3. 空の依存配列 `[]` の意味
「最初の1回だけ繋げばいいよ」というサインです。もしここに何も書かないと、画面が再描画されるたびに何回も外の世界と繋ぎ直してしまい、ブラウザが悲鳴を上げてしまいます。
—
4. つまずきがちなポイントと、温かいアドバイス
`useEffect`を学び始めると、こんな疑問や不安にぶつかるはずです。
- 「依存配列に何を書けばいいか分からない……」
- アドバイス: 基本のルールはシンプルです。「エフェクトの中で使っているReact変数は、全部依存配列の中に並べてあげる」。これだけです。迷ったらまずはエフェクトの中をじっくり見つめて、外から持ち込んでいる変数がないか探してみてくださいね。
- 「console.logが1つの動作に対して2回動く(React 18の仕様)」
- アドバイス: 近年のReactでは、将来の機能(画面の切り替えをスムーズにする仕組みなど)のテストのために、開発モード(StrictMode)のときだけ、マウント→即アンマウント→再マウントという動作をあえて裏側で行うことがあります。そのため、コンポーネントの初回の読み込み時にログが2回出ることがありますが、バグではないので安心してくださいね。 本番環境では1回しか呼ばれません。
—
おわりに
お疲れ様でした!
`useEffect`を使った「外部システムとの同期」について、イメージは膨らみましたでしょうか?
最初は「お城(React)の外と中を繋ぐ通訳さん」「自動ドアの電源と後片付け」のように、身近な比喩で頭の中で情景を思い浮かべてみてください。そうすると、コードの意図がスッと腑に落ちる瞬間がやってきます。
Reactでの開発は、最初は複雑に感じることも多いですが、一つひとつの仕組みが繋がっていくと、まるで自分の手で魔法の道具を作っているかのような最高のワクワク感が味わえます。
焦らず、ご自身のペースで一歩ずつ進んでいきましょう。
あなたのReact学習の旅を、心から応援しています!

コメント