React Hooks 入門【代表的なフック解説】useState から useEffect まで初心者向けに解説

React Hooksとは何か、種類と使い方を初心者向けにやさしく解説。useState・useEffect・useContextなど代表的なフックを実例コード付きで紹介します。

#react#hooks#javascript#frontend

「Reactを学び始めたら useState とか useEffect という不思議な関数が出てきて混乱した……」

そんな経験はありませんか?これらは React Hooks(フックス) と呼ばれる機能で、現代のReact開発では欠かせない存在です。

この記事では、Hooksの基本的な考え方から代表的なフックの役割まで、プログラミング初心者の方でもわかるように丁寧に解説します。

この記事でわかること:

  • React Hooksとは何か・なぜ必要なのか
  • 7つのカテゴリに分類された代表的なHooksの役割
  • 最もよく使う useState useEffect useContext の使い方
  • どのHooksから学べばいいかの学習ロードマップ

React Hooksって何?

React Hooksとは、関数コンポーネントの中でReactの機能を使えるようにする特別な関数です。

名前がすべて use で始まるのが特徴です(useState, useEffect など)。

Hooks登場前は何が大変だったの?

Hooks(React 16.8で登場)が登場する前は、状態管理や副作用処理をするためにはクラスコンポーネントという複雑な書き方が必要でした。

// Hooks登場前(クラスコンポーネント)- 複雑で読みにくい
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 }; // 状態はthis.stateに
  }
 
  render() {
    return (
      <button onClick={() => this.setState({ count: this.state.count + 1 })}>
        {this.state.count}回クリック
      </button>
    );
  }
}
// Hooks登場後(関数コンポーネント)- シンプルで読みやすい!
function Counter() {
  const [count, setCount] = useState(0);
 
  return (
    <button onClick={() => setCount(count + 1)}>
      {count}回クリック
    </button>
  );
}

Hooksのおかげで、コードがぐっとシンプルになりました。

Hooksを使うメリット・デメリット

メリット

  • 関数コンポーネントだけで完結するのでシンプルに書ける
  • ロジックをカスタムフックとして再利用できる
  • クラス構文(this)を覚えなくていい
  • テストが書きやすい

デメリット

  • ルール(条件分岐の中で使えない等)を守る必要がある
  • 種類が多いので最初は覚えることが多い
  • useEffectの依存配列など、ハマりやすいポイントがある

Hooksの2つの大原則

Hooksを使うときに必ず守るルールが2つあります。

  1. コンポーネントのトップレベルでのみ呼び出す → iffor の中で使ってはいけない
  2. React関数(コンポーネントまたはカスタムフック)の中でのみ呼び出す → 通常のJavaScript関数の中では使えない
// ❌ NG:条件分岐の中で使っている
function BadExample({ isLoggedIn }) {
  if (isLoggedIn) {
    const [name, setName] = useState(""); // エラーになる!
  }
}
 
// ✅ OK:トップレベルで使う
function GoodExample({ isLoggedIn }) {
  const [name, setName] = useState(""); // 常にトップレベルで
  if (!isLoggedIn) return null;
  return <p>{name}</p>;
}

代表的なHooksを7カテゴリで解説

Hooksは公式ドキュメントで7つのカテゴリに分類されています。一つずつ見ていきましょう。


1. ステートフック(状態管理)

コンポーネントに「記憶」を持たせるためのHooksです。

useState ★最重要

最もよく使うHookです。シンプルな状態を管理します。

const [状態変数, 更新関数] = useState(初期値);
function LikeButton() {
  const [liked, setLiked] = useState(false); // 初期値はfalse
 
  return (
    <button onClick={() => setLiked(!liked)}>
      {liked ? "❤️ いいね済み" : "🤍 いいね"}
    </button>
  );
}

useReducer

状態の更新ロジックが複雑になってきたときuseState の代わりに使います。更新のルールを「reducer(リデューサー)」という関数にまとめられます。

// countのプラス・マイナスをreducerで管理する例
function reducer(state, action) {
  switch (action.type) {
    case "increment": return { count: state.count + 1 };
    case "decrement": return { count: state.count - 1 };
    default: return state;
  }
}
 
function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
 
  return (
    <>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
      <span>{state.count}</span>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
    </>
  );
}

初心者へのアドバイス: まずは useState を使いこなしましょう。複雑になってきたら useReducer に切り替えるイメージでOKです。


2. コンテキストフック(コンテキスト)

Props のバケツリレー問題を解決するためのHooksです。

useContext ★よく使う

コンポーネントツリーの深い部分にデータを渡したいとき、useContext を使うと中間のコンポーネントを経由せずに直接受け取れます。

// テーマ情報を親から子孫に渡す例
const ThemeContext = React.createContext("light");
 
// どこからでもテーマ情報を受け取れる!
function ChildComponent() {
  const theme = useContext(ThemeContext);
  return <div className={theme}>テーマ: {theme}</div>;
}
 
// 親コンポーネントでProviderでラップする
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ChildComponent />
    </ThemeContext.Provider>
  );
}

3. Refフック(参照)

レンダリングに影響しない値を保持したり、DOMの要素を直接操作するためのHooksです。

useRef

主に2つの用途で使います:

用途①:DOM要素を直接操作する(例:フォームにフォーカス当てる)

function SearchForm() {
  const inputRef = useRef(null);
 
  const handleClick = () => {
    inputRef.current.focus(); // 検索ボックスにフォーカス!
  };
 
  return (
    <>
      <input ref={inputRef} type="text" placeholder="検索..." />
      <button onClick={handleClick}>フォーカス</button>
    </>
  );
}

用途②:再レンダリングを起こさずに値を保持する

function Timer() {
  const timerIdRef = useRef(null); // タイマーIDを保存(変わっても再描画しない)
 
  const start = () => {
    timerIdRef.current = setInterval(() => console.log("tick"), 1000);
  };
 
  const stop = () => {
    clearInterval(timerIdRef.current);
  };
 
  return (
    <>
      <button onClick={start}>開始</button>
      <button onClick={stop}>停止</button>
    </>
  );
}

useImperativeHandle

子コンポーネントのメソッドを親から呼び出せるようにするHookです。高度な使い方なので、最初は気にしなくてOKです。


4. エフェクトフック(副作用)

Reactの外の世界(API通信・タイマー・DOMの変更など)とやりとりするためのHooksです。

公式ドキュメントでは「エフェクトはReactパラダイムからの脱出ハッチ」と表現されています。必要なときだけ使いましょう。

useEffect ★重要

最もよく使うエフェクトです。コンポーネントが表示されたタイミングでデータを取得したり、外部システムと接続したりします。

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
 
  useEffect(() => {
    // コンポーネントが表示されたときにAPIを呼ぶ
    fetch(`/api/users/${userId}`)
      .then((res) => res.json())
      .then((data) => setUser(data));
 
    // クリーンアップ関数(コンポーネントが消えたときに実行)
    return () => {
      console.log("クリーンアップ");
    };
  }, [userId]); // [userId]:userIdが変わったときだけ再実行
 
  return <div>{user?.name ?? "読み込み中..."}</div>;
}

useEffect の第2引数(依存配列)がポイントです:

依存配列実行タイミング
なし毎回のレンダリング後
[](空配列)初回表示時のみ
[value]value が変わったとき

依存配列・クリーンアップ関数・よくあるトラブルなど、useEffect の詳しい解説は以下の記事をご覧ください。

useEffect 完全入門 - 副作用処理をやさしく解説

useLayoutEffect

useEffect とほぼ同じですが、ブラウザが画面を描画するに実行されます。要素のサイズ計測など、描画タイミングが重要な処理に使います。通常は useEffect で十分です。

useInsertionEffect

CSS-in-JSライブラリ作者向けの特殊なHookです。一般的なアプリ開発では使いません。


5. パフォーマンスフック(最適化)

不要な再計算や再レンダリングを防ぐためのHooksです。パフォーマンスの問題が出てから使うのがベストプラクティスです。

useMemo

重い計算処理の結果をキャッシュします。同じ入力なら再計算せずにキャッシュを返します。

function DataTable({ items, filter }) {
  // filterが変わったときだけ再計算する
  const filteredItems = useMemo(
    () => items.filter((item) => item.name.includes(filter)),
    [items, filter]
  );
 
  return <ul>{filteredItems.map((item) => <li key={item.id}>{item.name}</li>)}</ul>;
}

useCallback

関数の定義をキャッシュします。子コンポーネントに関数をpropsとして渡すときの不要な再レンダリングを防ぎます。

function Parent() {
  const [count, setCount] = useState(0);
 
  // countが変わっても handleClick の参照が変わらない
  const handleClick = useCallback(() => {
    console.log("クリック!");
  }, []); // 依存なしなので一度だけ生成
 
  return (
    <>
      <button onClick={() => setCount(count + 1)}>カウント: {count}</button>
      <ChildButton onClick={handleClick} /> {/* 不要な再レンダリングを防ぐ */}
    </>
  );
}

useTransition

状態の更新を優先度が低いものとしてマークします。入力フィールドなどの即時反応を維持しながら、重い更新処理を後回しにできます。

function SearchPage() {
  const [query, setQuery] = useState("");
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();
 
  const handleChange = (e) => {
    setQuery(e.target.value); // 入力は即時反映
    startTransition(() => {
      setResults(heavySearch(e.target.value)); // 検索は後回しOK
    });
  };
 
  return (
    <>
      <input value={query} onChange={handleChange} />
      {isPending ? <p>検索中...</p> : <ResultList results={results} />}
    </>
  );
}

useDeferredValue

値の更新を遅らせます。useTransition と似ていますが、こちらはを遅らせる用途です。


6. その他のフック

useId

サーバーとクライアントで一致するユニークなIDを生成します。フォームのラベルとinputを紐付けるときなどに便利です。

function EmailField() {
  const id = useId(); // 自動で一意のIDを生成
 
  return (
    <>
      <label htmlFor={id}>メールアドレス</label>
      <input id={id} type="email" />
    </>
  );
}

useDebugValue

カスタムHookにDevTools用のラベルをつけられます。開発時のデバッグに使います。

useSyncExternalStore

ReactのstateではなくReduxなどの外部ストアを読み込むときに使います。ライブラリ作者向けです。

useActionState

フォームのアクション結果(成功/失敗状態)を管理するHookです。React 19から追加されました。


カスタムフック:自分でHooksを作れる

複数のHooksを組み合わせて、再利用可能なカスタムHookを作ることもできます。名前は必ず use から始めます。

// データ取得の処理をカスタムフックとして切り出す
function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
 
  useEffect(() => {
    fetch(url)
      .then((res) => res.json())
      .then((data) => {
        setData(data);
        setLoading(false);
      })
      .catch((err) => {
        setError(err);
        setLoading(false);
      });
  }, [url]);
 
  return { data, loading, error };
}
 
// どのコンポーネントからも使いまわせる!
function UserList() {
  const { data, loading } = useFetch("/api/users");
  if (loading) return <p>読み込み中...</p>;
  return <ul>{data.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}

どのHooksから学べばいい?学習ロードマップ

    まとめ

    この記事で紹介した代表的なHooksを一覧でおさらいします。

    カテゴリHook用途優先度
    状態useStateシンプルな状態管理★★★
    状態useReducer複雑な状態管理★★
    コンテキストuseContextグローバルデータの受け取り★★★
    RefuseRefDOM操作・値の保持★★
    エフェクトuseEffectAPI通信・副作用処理★★★
    パフォーマンスuseMemo計算結果のキャッシュ
    パフォーマンスuseCallback関数のキャッシュ
    その他useIdユニークID生成

    最初は useStateuseEffectuseContext の3つをしっかり使いこなすことを目標にしてください。残りは必要になったタイミングで覚えれば大丈夫です!

    PR

    React公式ドキュメント(日本語)を読もう

    ja.react.dev は日本語で読めるReact公式ドキュメント。各Hooksのインタラクティブなサンプルが充実していて、初心者にもおすすめです。

    React公式ドキュメントを見る

    関連記事