【入門編】 カスタムフックにおける依存関係の管理と引数設計 – React実践ガイド

こんにちは!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と仲良くなっていってくださいね。応援しています!

コメント

タイトルとURLをコピーしました