こんにちは!Reactの学習、毎日お疲れ様です。
画面に文字を入力したらちゃんと動くし、ボタンを押したらパッと色が変わる……。Reactって、自分の手で魔法をかけているみたいで本当にワクワクしますよね。
でも、少しずつアプリを作っていくうちに、こんなモヤモヤを感じたことはありませんか?
「あれ……? 気づいたら、このコンポーネントの中身、状態(state)だらけになってない?」
「同じような入力フォームの処理、別の画面でも書いた気がするんだけど、コピペするしか道はないの……?」
大丈夫です、安心してください。そのモヤモヤを感じた瞬間こそ、あなたがReactの「次のステップ」へ進む扉を開いた証拠です。誰もが最初はそこで立ち止まるんですから。
今日は、そんなごちゃごちゃしがちなコンポーネントをスッキリお片付けして、おまけにあちこちで使い回せるようにしちゃう魔法のテクニック、「カスタムフック」の世界へご案内しますね。
—
1. コンポーネントが「ごちゃごちゃお化け屋敷」になる理由
まずは、私たちがよくやりがちな「あるある」からお話しさせてください。
例えば、Webサイトによくある「お名前」や「メールアドレス」を入力するフォームを想像してみてください。入力するたびに値が変わるし、エラーチェックもしなきゃいけない。これを全部ひとつのコンポーネントの中に書こうとすると……
- 「今何が入力されているか」を覚えておく `useState`
- 「入力が変わったとき」に動く関数
- 「送信ボタンが押されたとき」のバリデーション(チェック)処理
……と、画面を表示するためのHTML(JSX)とは関係ない「裏側の手続き」で、コードが埋め尽くされてしまいます。これではまるで、リビングの真ん中に洗濯物の山が置きっぱなしになっているようなもの。どこに何があるか分からなくなってしまいますよね。
2. カスタムフックってなに?(お弁当箱のたとえ)
そこで登場するのが「カスタムフック」です。
難しく考える必要はありません。カスタムフックとは一言でいうと、「よく使う状態管理のセットを、そっくりそのまま詰め込める『お弁当箱』」のようなものです。
例えば、「入力フォームを管理するセット」をお弁当箱に詰めておけば、お腹が空いたとき(=フォームを使いたいとき)に、パカッと開けるだけでいつでもどこでも同じ機能が使えます。
作るルールはたったの2つだけ。
1. 関数名の最初は、必ず `use` から始めること(例: `useForm`, `useCounter`)。
2. 中でふつうに `useState` や `useEffect` などのReactのフックを使うこと。
たったこれだけです。これだけで、Reactは「あ、こいつは特別なパーツだな」と認識してくれます。
—
3. 実践!「文字を入力して覚える」ロジックをお引越しさせてみよう
百聞は一見にしかず。実際にコードを見てみましょう。
今回は、「入力フォームに文字を打ち込むと、その文字をリアルタイムで保存して、ボタンを押すとリセットできる」という、よくある機能をカスタムフックに切り出してみます。
まずは、お引越しさせる前の「よくあるごちゃっとした状態」です。
引越し前:ひとつのファイルに全部詰め込んじゃった例
import { useState } from ‘react’;
function SimpleForm() {
// 状態管理がコンポーネントの中に直接いる
const [text, setText] = useState(”);
const handleChange = (e) => {
setText(e.target.value);
};
const handleReset = () => {
setText(”);
};
return (
いま入力したよ: {text}
);
}
このままでも動きますが、もし「別のページでも同じような入力欄を作りたい!」となったとき、この `useState` や `handleChange` をもう一度コピー&ペーストすることになります。それはちょっともったいないですよね。
そこで、この「文字を覚えて、変えて、リセットする」という一連の動きを、まるっとお弁当箱(カスタムフック)に詰め替えてみましょう!
—
引越し後:カスタムフックを作ってみよう
新しいファイル(例えば `useInputText.js` など)を作って、そこにロジックを逃がします。
import { useState } from ‘react’;
// 1. 名前の最初は必ず「use」から始めます
export function useInputText(initialValue = ”) {
// 状態の管理をここに閉じ込めます
const [text, setText] = useState(initialValue);
// 入力が変わったときの処理
const handleChange = (e) => {
setText(e.target.value);
};
// リセットする処理
const handleReset = () => {
setText(”);
};
// コンポーネント側で使いたい変数や関数を「お弁当箱の中身」として外に出す(returnする)
return {
text,
onChange: handleChange,
reset: handleReset,
};
}
どうでしょう? 中身はさっきのコンポーネントにあったものとほとんど同じですよね。ただ、画面に表示するHTML(JSX)を描くのをやめて、「データと操作用の関数をセットにして、外の世界に貸し出す準備をした」、それだけなんです。
—
仕上げ:コンポーネント側ですっきり使う
お弁当箱ができたので、元のコンポーネント側を書き換えてみます。
import React from ‘react’;
// さっき作ったカスタムフックをインポートします
import { useInputText } from ‘./useInputText’;
function SmartForm() {
// カスタムフックを呼び出すだけで、必要なものが全部手に入っちゃう!
const nameInput = useInputText();
const emailInput = useInputText(); // なんと、同じロジックを別の名前で何個でも使い回せます!
return (
プロフィール入力
{/ お名前の入力欄 /}
{/ メールアドレスの入力欄(同じロジックをスッキリ再利用!) /}
);
}
export default SmartForm;
見てください、このスッキリ感!
コンポーネント側は「画面にどう表示するか(UI)」だけに集中できるようになり、データの裏側の動きはすべてカスタムフックというお弁当箱の中に綺麗に片付けられました。
しかも、`nameInput` と `emailInput` のように、ひとつのカスタムフックを何回でも、別の場所で使い回すことができるんです。これが、カスタムフックの本当の強さであり、最高に気持ちいいところです。
—
4. チーフアーキテクトからのアドバイス:いつカスタムフックを作るべき?
「じゃあ、すべての `useState` を別ファイルに切り出さなきゃいけないの?」と思われるかもしれませんが、答えは「いいえ」です。
最初は、ひとつのコンポーネントの中に `useState` が書いてあって全く問題ありません。ただ、開発を進める中で、次のようなサインが見えてきたら、お引越しのタイミングです。
- 「あれ、このコード、他のコンポーネントでも全く同じように書いたぞ?」
- 「コンポーネントの中身が長すぎて、画面の見た目を探すのにスクロールしなきゃいけない……」
こうした「重複」や「複雑さ」に気づいたとき、そっと状態ロジックを切り出して、あなただけの便利なカスタムフックを作ってみてください。
最初は「ファイルを分けるの面倒だな」と感じるかもしれませんが、一度このスッキリ感と再利用の便利さを味わうと、もう元の書き方には戻れなくなっちゃいますよ(笑)。
一歩一歩、焦らずにあなたのペースでReactを楽しんでいきましょう。
それでは、また次回の現場の知恵袋でお会いしましょう!Happy Coding!

コメント