こんにちは!Reactの学習、楽しく進められていますか?
画面を自由に動かせるようになってくると、「お、私けっこうできるぞ!」というワクワク感が増してきますよね。
でも、しばらくコードを書いていると、なんだかモヤッとする壁にぶつかることがありませんか?
例えば、「同じような状態管理のコードをあっちこっちで書いてるな……そうだ、カスタムフックにまとめちゃおう!」と思い立って作ってみたものの、いざ使ってみたら「あれ? 値が古いままで更新されない…」「無限ループしてブラウザがフリーズした…?(冷や汗)」なんて経験、ありませんか?
大丈夫ですよ、まったく心配いりません。それはあなたがダメなのではなくて、Reactくんの「記憶の仕組み」と「お片付けのタイミング」をまだ完全に手懐けていないだけなんです。
今回は、そんなカスタムフックの「引数設計」と「依存関係(dependencies)の管理」について、身近なたとえ話を交えながら、優しく、そして現場で本当に役立つコツを紐解いていきましょう!
—
1. カスタムフックって、なに?(身近なたとえ)
まずは、カスタムフックの正体をスッキリさせておきましょう。
難しく考える必要はありません。カスタムフックとは、いわば「お気に入りの道具箱」です。
例えば、毎朝お化粧をするときに、ファンデーション、ビューラー、アイブロウ……と、いつも同じ手順で使うコスメたちがバラバラだと面倒ですよね。だから、それらをひとまとめにした「メイクポーチ(=カスタムフック)」を作っておくわけです。
ポーチさえあれば、リビングでも寝室でも、どこに持っていっても同じ手順でサッとメイクができますよね。Reactのカスタムフックもこれと全く同じで、「よく使う状態管理と処理のセット」をひとまとめにして、どこでも使い回せるようにする便利グッズなのです。
—
2. 失敗しがちなポイント:依存配列(`[]`)って、ぶっちゃけどんなルールなの?
カスタムフックを作るとき、そして `useEffect` や `useCallback` を使うとき、必ずと言っていいほど頭を悩ませるのが、末尾につける依存配列(例:`[userId]` みたいなやつ)です。
ここでお決まりのバグ、「あれ? 画面を切り替えても、古いユーザーのデータが表示され続けるぞ…?」 という現象が起きます。
なぜ古い情報が出ちゃうの?(お買い物のレシートのたとえ)
想像してみてください。あなたはカフェの店員さんです。
お客さんが「アイスコーヒーをください」と言って注文用紙(引数)を置いていきました。
ここで、あなたが「よし、この注文用紙に書いてある通りにコーヒーを作ろう!」とメモを貼っておきます。これがReactの依存配列です。
- 依存配列が空っぽ `[]` の場合:
あなたは最初にもらった「最初のお客さんの注文メモ」をずっと肌身離さず持っています。
あとから別のお客さんが「やっぱりホットティーで!」と言いにきても、あなたは最初に見たメモしか見ない頑固な店員さんなので、ずーーーっと冷たいアイスコーヒーを作り続けます。これが「古い値を掴み続けてしまうバグ」の正体です。
- 正しく依存関係を渡す場合:
お客さんが変わるたびに、「あ、次の人のメモに書き換えなきゃ!」と、依存配列に `[order]` と書いておきます。そうすれば、注文が変わるたびに新鮮な情報をキャッチして、正しい飲み物を作ることができますよね。
—
3. 実践!柔軟でバグらないカスタムフックの作り方
言葉だけだとフワッとしてしまうので、実際に「ユーザーのデータを安全に取得・管理する」カスタムフックを書いてみましょう。
初心者のうちは、「引数をどう渡せばいいか」「中で使っている変数をどう依存配列に入れたらいいか」迷いがちですが、一緒に見ていきましょうね。
サンプルコード:安全な引数設計と依存関係のフック
import { useState, useEffect } from ‘react’;
// 【カスタムフック】
// 引数として「取得したいユーザーのID(userId)」を受け取ります。
// これにより、このフックはどんなIDのユーザーでも対応できる柔軟性を持ちます。
function useUserProfile(userId) {
// 1. ユーザーデータを保持する状態
const [user, setUser] = useState(null);
// 2. 通信中かどうかを保持する状態
const [loading, setLoading] = useState(true);
// 3. エラーが発生したときの状態
const [error, setError] = useState(null);
useEffect(() => {
// IDが渡されていない場合は何もしない(安全装置)
if (!userId) return;
let isMounted = true; // メモリリーク(アンマウント後の状態更新)を防ぐおまじない
setLoading(true);
// データを取得する非同期処理
async function fetchUserData() {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(‘ユーザー情報の取得に失敗しました…’);
}
const data = await response.json();
// コンポーネントがまだ画面にいる場合だけ、状態を更新する
if (isMounted) {
setUser(data);
setError(null);
}
} catch (err) {
if (isMounted) {
setError(err.message);
}
} finally {
if (isMounted) {
setLoading(false);
}
}
}
fetchUserData();
// クリーンアップ関数:コンポーネントが消えたり、userIdが変わったりしたときに実行される
return () => {
isMounted = false;
};
}, [userId]);
// ↑【ここが超重要!】
// 依存配列に「userId」を入れています。
// これにより、「ユーザーA」から「ユーザーB」に画面が切り替わったとき、
// Reactくんが「おっ、userIdが変わったから、もう一回データを取リ直さなきゃ!」と気づいてくれます。
// コンポーネント側で使いたい状態や関数を、オブジェクトや配列として返す
return { user, loading, error };
}
このコードの優しいポイント解説
1. 引数で「外の世界」と繋がる
`useUserProfile(userId)` のように引数を受け取ることで、このフックは固定されたデータではなく、親から渡されたどんなIDにも柔軟に対応できるようになります。
2. 依存配列には「エフェクト内で使っている外部の変数」を素直に入れる
`useEffect` の中で `userId` を使っていますよね。だから、依存配列にも必ず `[userId]` を書きます。「迷ったら、中で使っている変数はとりあえず依存配列に入れてみる」くらいの気持ちで最初は大丈夫です!
3. `isMounted` という優しい気配り
通信が終わる前にユーザーが別のページに移動しちゃったとき、Reactは「おい、いない人に向けて `setUser` すんなよ!」と怒ることがあります。それを防ぐために、お掃除用のフラグ(`isMounted`)を仕込んでおくと、現場で「おっ、分かってるね!」と言われるコードになりますよ。
—
4. コンポーネント側での使い方のイメージ
先ほどのカスタムフックを、実際の画面(コンポーネント)でどう使うかも見ておきましょう。
import React, { useState } from ‘react’;
function ProfileScreen() {
const [currentId, setCurrentId] = useState(1);
// 自作したカスタムフックを呼び出すだけ!
// 内部の複雑な通信や状態管理のコードは、ぜーんぶフックの中に隠れています。
const { user, loading, error } = useUserProfile(currentId);
return (
マイページ
{/ ユーザーを切り替えるボタンたち /}
{/ 状態に応じた表示の切り替え /}
{loading &&
読み込み中だよ、ちょっと待ってね……🍵
}
{error &&
エラーだよ: {error}
}
{user && !loading && (
名前: {user.name}
メールアドレス: {user.email}
)}
);
}
export default ProfileScreen;
見てください、コンポーネント側がものすごくスッキリしましたよね!
画面を描画することだけに集中できて、面倒なデータ取得のロジックはぜーんぶカスタムフック(道具箱)にお任せできています。これが、Reactの設計において目指したい美しい姿です。
—
さいごに
カスタムフックの引数設計と依存関係の管理、いかがでしたでしょうか?
最初は「えっ、どの変数を依存配列に入れればいいの?」「引数はオブジェクトで渡すべき? 個別の値で渡すべき?」と頭がこんがらがって当たり前です。私も最初は何度も無限ループの罠にハマり、ブラウザを固まらせて冷や汗をかいていましたから(笑)。
でも、「フックは便利な道具箱」「依存配列は、中身が変わったときに合図を出すためのスイッチ」というイメージを持ってもらえると、少しずつ霧が晴れてくるはずです。
一つひとつ、自分の手で書いて動かして、「あ、ここで値が切り替わるんだな」と体感していくことが一番の近道です。焦らず、あなたのペースで楽しくReactと仲良くなっていってくださいね。応援しています!

コメント