こんにちは!Reactの学習、毎日お疲れ様です。
画面を作っていて「なんかこの処理、何回も動いちゃうな…」「画面を開いただけで無限ループしてブラウザが固まった!」なんて経験、ありませんか?……大丈夫です、それ、誰もが最初に通る「Reactの洗礼」ですから安心してください。
今日は、その原因の大きなカギを握る`useEffect`の「依存配列」と「プリミティブ値」について、難しい専門用語はなるべく置いておいて、身近な例えを交えながら優しく紐解いていきたいと思います。
肩の力を抜いて、コーヒーでも飲みながら一緒に見ていきましょう!
—
そもそも `useEffect` って何をしているの?
Reactでアプリを作っていると、「画面が表示されたタイミングでサーバーからデータを取ってきたい」「入力フォームの値が変わったら、タイトルを書き換えたい」といった、画面の見た目以外のオマケの仕事(これを「副作用」と呼びます)をさせたい場面がたくさん出てきます。
この「オマケの仕事」をお願いする魔法の呪文が `useEffect` です。
基本の形はこんな感じですね。
import { useEffect, useState } from ‘react’;
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
// ここに「オマケの仕事」を書きます
console.log(“画面が動いたよ!”);
}, []); // ←ここのカッコが「依存配列」です!
}
この `useEffect` の後ろにくっついている `[ ]` (依存配列)、これが今日の主役です。ここに何をいれるかによって、Reactがいつその仕事をするのかが決まります。
—
主役登場:プリミティブ値ってなに?
さて、テーマにある「プリミティブ値」という少しカッコいい言葉。難しく考える必要はありません。これは、JavaScriptにおける「これ以上分けられない、一番シンプルで純粋なデータ(値そのもの)」のことです。
具体的には以下の3つを思い出してください。
- 数値(例: `0`, `100`, `-5`)
- 文字列(例: `”こんにちは”`, `”apple”`)
- 真偽値(例: `true`, `false`)
オブジェクト(`{}`)や配列(`[]`)と違って、これらは「中身がそのまんま値」という特徴があります。
—
例え話:自動販売機の「お札の投入」で考えてみよう
このプリミティブ値と依存配列の関係を、身近な「自動販売機」に例えてみましょう。
あなたは自動販売機の前にいます。ジュースを買うために、お財布から千円札を一枚入れました。
自動販売機(React)の頭の中では、こんな監視員がスタンバイしています。
> 「前回入っていたお金の金額」と「今入っているお金の金額」をジッと見比べる監視員
- 前回:0円
- 今回:1000円
監視員はこう思います。「おっ、金額が変わったぞ!じゃあ、お釣りの計算や、ジュースのボタンをピカピカ光らせる仕事(`useEffect`の中身)をもう一回やろう!」
これが、依存配列にプリミティブ値(数値)を入れたときの挙動です。
JavaScriptはこれをどうやって判定しているの?
React(というかJavaScript)は、前回と今回を比べるときに `Object.is`(オブジェクト・イズ) という厳格な判定ルールを使っています。
これは、要するに「中身の数字や文字が、1ミリも違わず全く同じかどうか」をチェックする神経質な判定員だと思ってください。
- 前回が `”apple”` で、今回が `”apple”` だったら 👉 「一緒だね!仕事はしなくていいや」
- 前回が `10` で、今回が `11` だったら 👉 「あれ、違うぞ!仕事しなきゃ!」
この「変わったかどうか」を、プリミティブ値はめちゃくちゃ分かりやすく正確に教えてくれる優等生なんです。
—
実例コードで動きを見てみよう
百聞は一見に如かず。実際にコードを書いて、プリミティブ値がどうやって `useEffect` を動かすトリガーになっているか見てみましょう。
以下のコードを、お使いのReact環境(CodeSandboxやクローンしたアプリなど)にそのまま貼り付けて、ブラウザのコンソール画面(F12キーなどを押して開く画面)を見ながら動かしてみてください。
import { useState, useEffect } from ‘react’;
export default function PrimitiveEffectSample() {
// 1. プリミティブ値(数値)の状態を定義
const [count, setCount] = useState(0);
// 2. プリミティブ値(文字列)の状態を定義
const [name, setName] = useState(‘たろう’);
// count(数値)の変化を監視する useEffect
useEffect(() => {
console.log(`【監視中】countの値が変わりました!今の数値を再確認:${count}`);
// ここに「countが変わったときだけにやりたい処理」を書きます
// 例:APIを叩く、タイマーをリセットするなど
}, [count]); // ← 依存配列にプリミティブ値の「count」を指定!
return (
プリミティブ値とuseEffectの実験場
現在のカウント: {count}
現在の名前: {name}
{/ あえて「同じ名前」をセットするボタンも用意しました /}
);
}
動かしてみたときの挙動のポイント
1. 「カウントを増やす」ボタンを押したとき
`count` が `0` から `1` に変わります。プリミティブ値(数値)が変わったため、Reactは「おっ、値が更新されたな」と察知し、`useEffect` の中身(コンソールログ)が実行されます。
2. 「『たろう』に名前をセットする」ボタンを押したとき
すでに名前は `たろう` ですが、もう一度同じ `たろう` をセットしてみます。
ここで注目! コンソールログは実行されません。
なぜなら、`Object.is` で比較したとき、「前回も今回も文字列の『たろう』で、1ミリも変わってないじゃん!」とReactが判断し、無駄な再実行をサボってくれる(スキップしてくれる)からです。なんてお利口さんなんでしょう!
3. 「『じろう』に名前を変える」ボタンを押したとき
文字列が `たろう` から `じろう` に変わります。これは変化があるので、もし名前を監視する `useEffect` があれば、そこがしっかり反応します。
—
つまずきやすいポイントと優しいアドバイス
初心者の方がここでよくやってしまうミス、そしてそこからの抜け出し方をお伝えしておきますね。
つまずき①:依存配列を書き忘れて、毎回実行されちゃう
依存配列 `[ ]` 自体を書き忘れたり、空っぽにすべきところで変数を入れ忘れたりすると、コンポーネントが描画されるたびに `useEffect` が爆発的に実行されてしまいます。
もし「画面が重いな」「無限ループしてる?」と思ったら、まずはこの依存配列の中身を疑ってみてください。
つまずき②:「同じ値なのに、なぜか再実行される…?」
プリミティブ値(数値や文字列)を使っているうちは大丈夫なのですが、今後もしオブジェクト(`{}`)や配列(`[]`)を依存配列に入れたとき、「中身は同じなのに、なぜか毎回 `useEffect` が動いちゃう現象」にぶぶつかります。
これはオブジェクトや配列が「中身が同じでも、メモリー上の住所が違うと別物判定される」というちょっぴり複雑な仕組みを持っているからです。
でも、今日お勉強した「数値・文字列・真偽値のプリミティブ値なら、 `Object.is` が純粋に中身を見てくれるから安心なんだ」という基本を知っていれば、その壁にぶつかったときも「あ、今回はオブジェクトだからだ!」とすぐに気づけるはずです。
—
まとめ
- `useEffect` の依存配列は、いわば「お仕事のトリガーを決める監視員」。
- 数値・文字列・真偽値などの「プリミティブ値」をここに置くと、Reactは `Object.is` という仕組みで「値が本当に変わったかどうか」をめちゃくちゃ正確にチェックしてくれる。
- 値が変わっていなければ、無駄に仕事を実行せずスルーしてくれるので、パフォーマンス的にも非常に安全。
Reactのルールに最初は戸惑うこともあるかもしれませんが、ひとつひとつの仕組みは私たちの日常の感覚ととてもよく似ています。
「あ、Reactくん、ちゃんと前回と違うか確認してくれてるんだな」と、可愛い相棒のように付き合ってあげてくださいね。
あなたのReact開発が、少しでも楽しく、スムーズになりますように。
それではまた次の記事でお会いしましょう!

コメント