コンテンツにスキップ

React Hooks 完全ガイド

React Hooksを基礎から実践まで完全マスターするための日本語ガイド CDNで実行可能なサンプルコード付き


目次

  1. React Hooksとは
  2. CDNでReactを使う方法
  3. useState - 状態管理
  4. useEffect - 副作用処理
  5. useContext - グローバル状態共有
  6. useMemo - 計算結果のメモ化
  7. useCallback - 関数のメモ化
  8. useRef - DOM参照と永続値
  9. useReducer - 複雑な状態管理
  10. Custom Hooks - カスタムフック
  11. Hooks一覧表
  12. ベストプラクティス

React Hooksとは

React Hooks(フックス) は、関数コンポーネントでReactの機能を使うための「魔法の関数」です。

Hooksが解決する問題

  • クラスコンポーネントの複雑さを排除: thisの煩わしさから解放
  • ロジックの再利用: 関数として切り出し可能
  • コードの可読性向上: シンプルで理解しやすい

Hooksの基本ルール

  1. トップレベルでのみ呼び出す: ループや条件分岐の中で使わない
  2. 関数コンポーネント内で使う: 通常の関数では使えない
  3. 名前はuseで始める: カスタムフックを作るときの約束

CDNでReactを使う方法

Node.jsやビルドツールがなくても、CDNを読み込めばReactを動かせます。 以下の3行をHTMLに書くだけでOK。

<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

重要ポイント: - HTML内でReactコードを書くときは <script type="text/babel"> を使うとJSXが動きます - これはCSR(Client Side Rendering)です - サーバーサイドレンダリング(SSR)は動きませんが、練習・理解には最適


useState - 状態管理

概念

useState は、Reactが値を覚えてくれる(状態管理)Hookです。

Hook 役割 たとえ
useState Reactが変数を覚えてくれる 「覚えておくメモ帳」

使うタイミング

  • コンポーネント内で値を保持したいとき
  • ユーザーの入力や操作で値が変わるとき
  • 値の変更に応じて画面を再レンダリングしたいとき

CDN実行サンプル

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>useState基本例</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      function App() {
        const [count, setCount] = React.useState(0);

        return (
          <div>
            <h1>カウント: {count}</h1>
            <button onClick={() => setCount(count + 1)}>増やす</button>
            <button onClick={() => setCount(count - 1)}>減らす</button>
            <button onClick={() => setCount(0)}>リセット</button>
          </div>
        );
      }

      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
  </body>
</html>

ベストプラクティス

// ✅ 良い例: 前の状態を使う場合は関数形式
setCount((prevCount) => prevCount + 1);

// ❌ 悪い例: 連続で更新すると意図しない結果に
setCount(count + 1);
setCount(count + 1); // これは2回加算されない

useEffect - 副作用処理

概念

useEffect は、状態が変わった後に実行される(副作用)Hookです。

Hook 役割 たとえ
useEffect 副作用(API呼び出しやDOM操作)を行う 「何かが変わったら動くスイッチ」

使うタイミング

  • コンポーネントのマウント時に処理を実行したいとき
  • 特定の値が変更されたときに処理を実行したいとき
  • データフェッチ、購読の設定、タイマーなど

CDN実行サンプル

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>useState & useEffect</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      function App() {
        const [count, setCount] = React.useState(0);

        React.useEffect(() => {
          console.log("カウントが変わった:", count);
          document.title = `カウント: ${count}`;
        }, [count]);

        return (
          <div>
            <h1>カウント: {count}</h1>
            <button onClick={() => setCount(count + 1)}>増やす</button>
          </div>
        );
      }

      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
  </body>
</html>

依存配列のパターン

// パターン1: マウント時のみ実行
React.useEffect(() => {
  console.log("初回レンダリング時のみ");
}, []);

// パターン2: 特定の値が変わったときのみ
React.useEffect(() => {
  console.log("countが変わった");
}, [count]);

// パターン3: 毎回実行(非推奨)
React.useEffect(() => {
  console.log("毎回実行される");
});

クリーンアップ関数

React.useEffect(() => {
  const timer = setInterval(() => {
    console.log("1秒経過");
  }, 1000);

  // クリーンアップ: コンポーネントがアンマウントされるときに実行
  return () => {
    clearInterval(timer);
  };
}, []);

ベストプラクティス

// ✅ 良い例: 依存配列を正しく設定
React.useEffect(() => {
  fetchData(userId);
}, [userId]);

// ❌ 悪い例: 依存配列を空にすると無限ループの危険
React.useEffect(() => {
  setCount(count + 1); // これは無限ループになる
}, [count]);

useContext - グローバル状態共有

概念

useContext は、親から子に毎回propsで渡さなくても済む、アプリ全体で共有できる「共通データの保管庫」です。

Hook 役割 たとえ
useContext コンテキストの値を取り出す 「共有冷蔵庫からジュース取る」

使うタイミング

  • テーマ(ダークモード/ライトモード)の共有
  • ログインユーザー情報の共有
  • 多階層にわたるpropsのバケツリレーを避けたいとき

CDN実行サンプル

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>useContext</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      const ThemeContext = React.createContext("light");

      function Child() {
        const theme = React.useContext(ThemeContext);
        return <p>現在のテーマ: {theme}</p>;
      }

      function App() {
        return (
          <ThemeContext.Provider value="dark">
            <h1>Contextの例</h1>
            <Child />
          </ThemeContext.Provider>
        );
      }

      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
  </body>
</html>

より実践的な例

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>useContext - テーマ切り替え</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      const ThemeContext = React.createContext();

      function ThemeProvider({ children }) {
        const [theme, setTheme] = React.useState("light");

        const toggleTheme = () => {
          setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
        };

        return (
          <ThemeContext.Provider value={{ theme, toggleTheme }}>
            {children}
          </ThemeContext.Provider>
        );
      }

      function ThemedComponent() {
        const { theme, toggleTheme } = React.useContext(ThemeContext);

        const style = {
          backgroundColor: theme === "light" ? "#fff" : "#333",
          color: theme === "light" ? "#000" : "#fff",
          padding: "20px",
        };

        return (
          <div style={style}>
            <h1>現在のテーマ: {theme}</h1>
            <button onClick={toggleTheme}>テーマを切り替え</button>
          </div>
        );
      }

      function App() {
        return (
          <ThemeProvider>
            <ThemedComponent />
          </ThemeProvider>
        );
      }

      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
  </body>
</html>

ベストプラクティス

// ✅ 良い例: Contextをカスタムフックでラップ
function useTheme() {
  const context = React.useContext(ThemeContext);
  if (!context) {
    throw new Error("useTheme must be used within a ThemeProvider");
  }
  return context;
}

// 使用時
const { theme, toggleTheme } = useTheme();

useMemo - 計算結果のメモ化

概念

useMemo は、計算結果をキャッシュする(重い処理向け)Hookです。

Hook 役割 たとえ
useMemo 計算結果を覚えて再利用する 「前回の答えをメモしておく」

使うタイミング

  • 計算コストが高い処理の結果を保存したいとき
  • 参照の同一性を保ちたいとき(オブジェクトや配列)
  • 不要な再計算を避けたいとき

CDN実行サンプル

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>useMemo</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      function App() {
        const [count, setCount] = React.useState(0);
        const [input, setInput] = React.useState("");

        // countが変わった時のみ再計算される
        const double = React.useMemo(() => {
          console.log("再計算中…");
          return count * 2;
        }, [count]);

        return (
          <div>
            <h1>useMemoの例</h1>
            <p>count: {count}</p>
            <p>double: {double}</p>
            <button onClick={() => setCount(count + 1)}>増やす</button>
            <hr />
            <p>inputを変更してもdoubleは再計算されない</p>
            <input
              type="text"
              value={input}
              onChange={(e) => setInput(e.target.value)}
              placeholder="ここに入力"
            />
          </div>
        );
      }

      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
  </body>
</html>

ベストプラクティス

// ✅ 良い例: 重い計算をメモ化
const expensiveValue = React.useMemo(() => {
  return items.filter(item => item.price > 1000)
               .map(item => item.price * 1.1);
}, [items]);

// ❌ 悪い例: 単純な計算には不要(むしろオーバーヘッド)
const simple = React.useMemo(() => count + 1, [count]);

useCallback - 関数のメモ化

概念

useCallback は、関数をキャッシュする(再レンダリング防止)Hookです。

Hook 役割 たとえ
useCallback 関数をメモ化する 「同じ関数を毎回作らずに再利用」

使うタイミング

  • 子コンポーネントに関数をpropsとして渡すとき
  • useEffectの依存配列に関数を入れるとき
  • 無駄な再レンダリングを防ぎたいとき

CDN実行サンプル

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>useMemo & useCallback</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      function App() {
        const [count, setCount] = React.useState(0);

        const double = React.useMemo(() => {
          console.log("再計算中…");
          return count * 2;
        }, [count]);

        const handleClick = React.useCallback(() => {
          setCount((c) => c + 1);
        }, []);

        return (
          <div>
            <h1>useMemo/useCallbackの例</h1>
            <p>count: {count}</p>
            <p>double: {double}</p>
            <button onClick={handleClick}>増やす</button>
          </div>
        );
      }

      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
  </body>
</html>

ベストプラクティス

// ✅ 良い例: 子コンポーネントに渡す関数をメモ化
const handleClick = React.useCallback(() => {
  doSomething(id);
}, [id]);

return <ChildComponent onClick={handleClick} />;

// ❌ 悪い例: インライン関数は毎回新しく作られる
return <ChildComponent onClick={() => doSomething(id)} />;

useRef - DOM参照と永続値

概念

useRef は、DOMや変数を直接参照するHookです。

Hook 役割 たとえ
useRef DOMや変数を直接参照 「メモをポケットに入れておく」

使うタイミング

  • DOM要素に直接アクセスしたいとき
  • 再レンダリングをトリガーせずに値を保持したいとき
  • 前回の値を覚えておきたいとき

CDN実行サンプル

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>useRef</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      function App() {
        const inputRef = React.useRef(null);
        const countRef = React.useRef(0);

        const focusInput = () => {
          inputRef.current.focus();
        };

        const incrementRef = () => {
          countRef.current += 1;
          console.log("Ref count:", countRef.current);
          // 注意: この変更は再レンダリングをトリガーしない
        };

        return (
          <div>
            <h1>useRefの例</h1>
            <input ref={inputRef} type="text" placeholder="テキスト入力" />
            <button onClick={focusInput}>インプットにフォーカス</button>
            <hr />
            <button onClick={incrementRef}>Refカウント増加再レンダリングなし</button>
            <p>コンソールを確認してください</p>
          </div>
        );
      }

      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
  </body>
</html>

ベストプラクティス

// ✅ 良い例: DOM操作
const inputRef = React.useRef(null);
inputRef.current.focus();

// ✅ 良い例: 前回の値を保持
const prevCountRef = React.useRef();
React.useEffect(() => {
  prevCountRef.current = count;
}, [count]);

// ❌ 悪い例: レンダリング中にrefを変更しない
function Component() {
  const ref = React.useRef(0);
  ref.current += 1; // これはNG
  return <div>{ref.current}</div>;
}

useReducer - 複雑な状態管理

概念

useReducer は、状態管理をもう少し複雑にやるHookです。

Hook 役割 たとえ
useReducer 状態管理をもう少し複雑にやる 「司令官が指示を出して部下が状態を変える」

使うタイミング

  • 複数の関連する状態を管理するとき
  • 次の状態が前の状態に依存するとき
  • 状態の更新ロジックが複雑なとき

CDN実行サンプル

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>useReducer</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      function reducer(state, action) {
        switch (action.type) {
          case "increment":
            return { count: state.count + 1 };
          case "decrement":
            return { count: state.count - 1 };
          case "reset":
            return { count: 0 };
          default:
            throw new Error("Unknown action type");
        }
      }

      function App() {
        const [state, dispatch] = React.useReducer(reducer, { count: 0 });

        return (
          <div>
            <h1>useReducerの例</h1>
            <p>カウント: {state.count}</p>
            <button onClick={() => dispatch({ type: "increment" })}>増やす</button>
            <button onClick={() => dispatch({ type: "decrement" })}>減らす</button>
            <button onClick={() => dispatch({ type: "reset" })}>リセット</button>
          </div>
        );
      }

      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
  </body>
</html>

ベストプラクティス

// ✅ 良い例: アクションタイプを定数で定義
const ACTIONS = {
  INCREMENT: "increment",
  DECREMENT: "decrement",
  RESET: "reset",
};

dispatch({ type: ACTIONS.INCREMENT });

// ✅ 良い例: payloadを使ってデータを渡す
dispatch({ type: "addTodo", payload: { text: "新しいタスク" } });

function reducer(state, action) {
  switch (action.type) {
    case "addTodo":
      return {
        todos: [...state.todos, { id: Date.now(), text: action.payload.text }],
      };
    default:
      return state;
  }
}

Custom Hooks - カスタムフック

概念

カスタムフック は、既存のHooksを組み合わせて「再利用できる関数」を自作できる仕組みです。

Hook 役割 たとえ
カスタムフック これらを組み合わせて自作したフック 「自分用の便利ツール」

使うタイミング

  • 複数のコンポーネントで同じロジックを使いたいとき
  • 状態管理のロジックを分離したいとき
  • コンポーネントをシンプルに保ちたいとき

命名規則

  • 必ずuseで始める: これはReactの約束事
  • camelCase: useFetch, useTimer, useLocalStorage

CDN実行サンプル1: useWaterStatus

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>カスタムフック</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      function useWaterStatus() {
        const [thirst, setThirst] = React.useState(true);
        const drink = () => setThirst(false);
        const dry = () => setThirst(true);
        return { thirst, drink, dry };
      }

      function App() {
        const { thirst, drink, dry } = useWaterStatus();

        return (
          <div>
            <h1>{thirst ? "のどが渇いた💦" : "満たされた💧"}</h1>
            <button onClick={drink}>水を飲む</button>
            <button onClick={dry}>乾く</button>
          </div>
        );
      }

      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
  </body>
</html>

CDN実行サンプル2: カスタムフック + useMemo

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>カスタムフック + useMemo</title>
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script type="text/babel">
      function useWaterStatus() {
        const [thirst, setThirst] = React.useState(true);
        return {
          thirst,
          drink: () => setThirst(false),
          dry: () => setThirst(true),
        };
      }

      function App() {
        const { thirst, drink, dry } = useWaterStatus();

        const message = React.useMemo(() => {
          return thirst ? "のどが渇いた💦" : "満たされた💧";
        }, [thirst]);

        return (
          <div>
            <h1>{message}</h1>
            <button onClick={dry}>乾く</button>
            <button onClick={drink}>水を飲む</button>
          </div>
        );
      }

      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
  </body>
</html>

実践的なカスタムフック例

useToggle

function useToggle(initialValue = false) {
  const [value, setValue] = React.useState(initialValue);
  const toggle = React.useCallback(() => setValue((v) => !v), []);
  return [value, toggle];
}

// 使用例
function App() {
  const [isOpen, toggleOpen] = useToggle(false);
  return (
    <div>
      <button onClick={toggleOpen}>
        {isOpen ? "閉じる" : "開く"}
      </button>
      {isOpen && <div>コンテンツが表示されています</div>}
    </div>
  );
}

useLocalStorage

function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = React.useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  const setValue = (value) => {
    try {
      const valueToStore =
        value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue];
}

// 使用例
function App() {
  const [name, setName] = useLocalStorage("name", "");
  return (
    <input
      value={name}
      onChange={(e) => setName(e.target.value)}
      placeholder="名前を入力"
    />
  );
}

useFetch

function useFetch(url) {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        const json = await response.json();
        setData(json);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

// 使用例
function App() {
  const { data, loading, error } = useFetch(
    "https://jsonplaceholder.typicode.com/posts/1"
  );

  if (loading) return <div>読み込み中...</div>;
  if (error) return <div>エラー: {error.message}</div>;
  return <div>{data.title}</div>;
}

ベストプラクティス

// ✅ 良い例: ロジックを分離して再利用可能に
function useAuth() {
  const [user, setUser] = React.useState(null);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    // 認証状態を確認
    const unsubscribe = auth.onAuthStateChanged((user) => {
      setUser(user);
      setLoading(false);
    });
    return unsubscribe;
  }, []);

  return { user, loading };
}

// ❌ 悪い例: useで始まらない名前
function getUser() { // これはカスタムフックではない
  const [user, setUser] = React.useState(null);
  return user;
}

Hooks一覧表

基本Hooks

Hook 説明 たとえ
useState 状態(変数)をReactに覚えさせる 「覚えておくメモ帳」
useEffect 副作用(API呼び出しやDOM操作)を行う 「何かが変わったら動くスイッチ」
useContext コンテキストの値を取り出す 「共有冷蔵庫からジュース取る」

パフォーマンス最適化Hooks

Hook 説明 たとえ
useMemo 計算結果を覚えて再利用する 「前回の答えをメモしておく」
useCallback 関数をメモ化する 「同じ関数を毎回作らずに再利用」

特殊用途Hooks

Hook 説明 たとえ
useRef DOMや変数を直接参照 「メモをポケットに入れておく」
useReducer 状態管理をもう少し複雑にやる 「司令官が指示を出して部下が状態を変える」

カスタムHooks

Hook 説明 たとえ
カスタムフック これらを組み合わせて自作したフック 「自分用の便利ツール」

ベストプラクティス

1. Hooksの順序を守る

// ✅ 良い例: トップレベルで使う
function Component() {
  const [count, setCount] = React.useState(0);
  const [name, setName] = React.useState("");

  return <div>{count}</div>;
}

// ❌ 悪い例: 条件分岐の中で使う
function Component() {
  if (condition) {
    const [count, setCount] = React.useState(0); // NG
  }
  return <div>Hello</div>;
}

2. useEffectの依存配列を正確に

// ✅ 良い例: 必要な依存をすべて含める
React.useEffect(() => {
  fetchData(userId);
}, [userId]);

// ❌ 悪い例: 依存配列が不足
React.useEffect(() => {
  fetchData(userId);
}, []); // userIdが変わっても実行されない

3. カスタムフックで再利用性を高める

// ✅ 良い例: ロジックを分離
function useWindowSize() {
  const [size, setSize] = React.useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  React.useEffect(() => {
    const handleResize = () => {
      setSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  return size;
}

4. useMemo/useCallbackは必要な時だけ

// ✅ 良い例: 重い計算をメモ化
const filteredList = React.useMemo(() => {
  return items.filter(item => item.price > 1000);
}, [items]);

// ❌ 悪い例: 単純な計算にはオーバーヘッド
const total = React.useMemo(() => a + b, [a, b]); // 不要

5. useRefは再レンダリングが不要な値に

// ✅ 良い例: DOM参照や前回の値
const inputRef = React.useRef(null);
const prevCountRef = React.useRef();

// ❌ 悪い例: 画面に表示する値はuseState
const countRef = React.useRef(0); // 画面に表示するならuseStateを使うべき

学習の順序

  1. useState → 基本中の基本
  2. useEffect → 副作用を理解する
  3. useContext → グローバル状態を学ぶ
  4. useMemo / useCallback → 最適化を学ぶ
  5. useRef → DOM操作を学ぶ
  6. useReducer → 複雑な状態管理を学ぶ
  7. Custom Hooks → 再利用可能なロジックを作る

よくある問題と解決策

問題 原因 解決策
useEffectがループする 依存配列が間違っている [依存するstateだけ] にする
再レンダリングが多い propsや関数を都度生成している useMemo / useCallback で固定
状態が更新されない 非同期処理のタイミング問題 useEffectで適切に処理する
カスタムフックが動かない 命名がuseで始まっていない 必ずuseで始める

フォルダ構成・命名ルール

推奨フォルダ構成

src/
 ┣ components/   ← UIの部品(Button.jsx, Card.jsx)
 ┣ hooks/        ← カスタムフック(useFetch.js, useTimer.js)
 ┣ contexts/     ← Context管理(ThemeContext.js)
 ┣ pages/        ← 各ページ(Home.jsx, About.jsx)
 ┣ App.jsx       ← ルートコンポーネント
 ┗ index.js      ← ReactDOM.render()する入口

命名ルール

種類 命名ルール
コンポーネント PascalCase UserCard
Hook camelCase + "use" useFetch, useTimer
Context PascalCase + "Context" ThemeContext
CSS .module.css(Next.js推奨) Button.module.css

まとめ

React Hooksは、関数コンポーネントでReactの強力な機能を使うための仕組みです。

重要ポイント

  1. useState: 状態を管理する基本のHook
  2. useEffect: 副作用を扱う重要なHook
  3. useContext: グローバルな状態共有
  4. useMemo/useCallback: パフォーマンス最適化
  5. useRef: DOM操作や永続値の保持
  6. useReducer: 複雑な状態管理
  7. Custom Hooks: 再利用可能なロジックの作成

学習のコツ

  • CDNで小さい実験をする: 環境構築で迷わない
  • コンソールにconsole.log()を入れて動きを観察: 動きを理解する
  • 毎日1フックずつ覚える: useState → useEffect → useContext → useMemo
  • コードに日本語コメントを書く: 理解を深める
  • 動かして・壊して・直して覚える: 実践が最短

Reactは「動かして・壊して・直して」覚えるのが最短です。

このガイドのサンプルコードをコピーして、ブラウザで実行してみてください。 理解が深まったら、自分なりのカスタムフックを作ってみましょう。