↩️

Reactの代表的なフック

に公開

はじめに

フックを用いると、コンポーネントからReactの様々な機能が利用できるようになります。
組み込みのフックを利用することも、独自にカスタマイズしたフックを作って再利用することも可能です。
https://ja.react.dev/reference/react/hooks

主要なフックを把握しておくことで、要件に合わせた選択ができるようになります。
ここでは代表的なフックとその具体例を紹介します。

useState

状態管理を行うためのフックです。
カウンターやフォーム入力値の保持など、コンポーネント内で値を管理したいときに利用します。

import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>現在のカウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

useEffect

副作用処理を記述するためのフックです。
データの取得、イベントリスナーの登録・解除、外部ライブラリとの連携などに利用されます。

import { useEffect, useState } from "react";

export default function User() {
  const [user, setUser] = useState<{ name: string } | null>(null);

  useEffect(() => {
    fetch("/api/user")
      .then((res) => res.json())
      .then((data) => setUser(data));
  }, []); // マウント時のみ実行

  return <div>{user ? `ユーザー: ${user.name}` : "読み込み中..."}</div>;
}

useContext

コンテキストの値を取得するためのフックです。
親コンポーネントから深い階層の子コンポーネントにデータを渡すときに便利です。

import { createContext, useContext } from "react";

const ThemeContext = createContext("light");

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

export default function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Child />
    </ThemeContext.Provider>
  );
}

useReducer

複雑な状態管理を行いたいときに利用します。
useStateよりも状態遷移を明確に管理でき、Reduxに似た仕組みを小規模に導入できます。

import { useReducer } from "react";

type State = { count: number };
type Action = { type: "increment" } | { type: "decrement" };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

export default function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </>
  );
}

useMemo

計算コストの高い処理をメモ化し、不要な再計算を防ぎます。
レンダリング最適化に効果的です。

import { useMemo, useState } from "react";

export default function ExpensiveCalculation() {
  const [num, setNum] = useState(1);

  const squared = useMemo(() => {
    console.log("計算中...");
    return num * num;
  }, [num]);

  return (
    <div>
      <p>{num} の2乗 = {squared}</p>
      <button onClick={() => setNum(num + 1)}>+1</button>
    </div>
  );
}

useCallback

関数をメモ化し、不要な再生成を防ぎます。
特に子コンポーネントへコールバックを渡す際に有効です。

import { useCallback, useState } from "react";

function Child({ onClick }: { onClick: () => void }) {
  return <button onClick={onClick}>クリック</button>;
}

export default function App() {
  const [count, setCount] = useState(0);

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

  return (
    <>
      <p>Count: {count}</p>
      <Child onClick={handleClick} />
    </>
  );
}

useRef

DOM要素や値を参照するために利用します。
document.getElementByIdのような操作をReactらしく書けます。

import { useRef } from "react";

export default function InputFocus() {
  const inputRef = useRef<HTMLInputElement>(null);

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

  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>フォーカス</button>
    </>
  );
}

まとめ

フックはReact開発における基本的な仕組みであり、それぞれの特徴と用途を理解することで、より効率的でメンテナンス性の高いコードが書けるようになります。
最初はuseStateuseEffectを中心に触れ、徐々に他のフックも試してみると理解しやすいです。

Discussion