React Hooksとは?初心者でもわかる実践的な入門ガイド

はじめに

Reactは、コンポーネント単位でUIを作りやすい仕組みが特徴ですね。 かつてはクラスコンポーネントを使うケースが多かったのですが、コードが複雑になりやすい面がありました。 そんな中で登場したのがReact Hooksという仕組みです。 関数コンポーネントでも状態管理やライフサイクルに関わる処理が簡潔に書けるようになります。 皆さんもReactを学ぶ上で、Hooksをどう使いこなすかは大切なポイントではないでしょうか。

この記事を読むとわかること

  • React Hooksの概要
  • よく使われる代表的なHooksの使い方
  • 実務での具体的な活用シーン
  • Hooksを使う際の注意点

React Hooksとは

React Hooksとは、関数コンポーネント内でReactの機能を利用できるようにする仕組みです。 たとえば状態を保持する、コンポーネントの描画タイミングに合わせた処理を行うなど、従来はクラスコンポーネントで行っていた内容をシンプルに実装できます。 Hooksを利用することで、状態管理のためだけにクラスを書かずに済むため、より短くわかりやすいコードを書きやすくなるのが特徴です。 また、複数の副作用(API呼び出しやイベントリスナー管理など)を適切に分割できるので、コードの分担もしやすくなります。

React Hooksの背景

Reactがクラスコンポーネントを用いていた頃、ライフサイクルメソッドにロジックが集中してしまう問題がよく起こりました。 コンポーネントが大規模になると、どの処理がどのライフサイクルメソッドで動いているのか追いかけづらくなることがあったのです。 そこでHooksが導入され、関数コンポーネントでも簡潔にライフサイクルを扱えるようになりました。 これによって、機能ごとにコードを分割しやすくなるメリットが生まれたと言えます。

なぜHooksが注目されるのか

Hooksを使うと、状態管理と副作用の処理が密結合になりすぎない構造を作りやすいと言われています。 また、テストもしやすくなるケースが多く、複数人での開発でもコードの意図を共有しやすいでしょう。 さらに関数コンポーネントがメインになるため、コンポーネント間のデータ受け渡しやロジックの切り分けを整理しやすくなります。 こうした点が注目を集める理由になっています。

よく使われるHooksの例

Reactには複数のHooksがありますが、まずは代表的なものを押さえるのが近道でしょう。 状態管理や副作用の制御など、実務でもすぐに役立つものが多いです。 特にuseStateuseEffectは、Reactを使い始めたばかりの方でもよく目にするはずです。

useState

useStateは、コンポーネント内で状態(state)を管理するためのHooksです。 クラスコンポーネントで言うところのthis.stateに相当し、値を保持したり更新したりすることができます。 例えば、ボタンをクリックするとカウントが増えるアプリなど、ちょっとした状態変化を管理するときに手軽に使われています。

import React, { useState } from "react";

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

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>現在のカウント: {count}</p>
      <button onClick={handleClick}>カウントを増やす</button>
    </div>
  );
}

export default Counter;

ボタンを押すたびにcountが更新され、画面に表示される数字も変化します。 コードがシンプルなので、初心者でも状態管理の流れをつかみやすいでしょう。

useEffect

useEffectは、副作用処理(APIの呼び出しやイベントリスナーの登録など)を行うためのHooksです。 コンポーネントが描画されたタイミングや、特定の状態が変化したタイミングで処理を実行したいときに利用します。 従来のクラスコンポーネントでいうcomponentDidMountやcomponentDidUpdateに相当する機能を、1つの関数内でわかりやすく管理できます。

import React, { useState, useEffect } from "react";

function FetchDataExample() {
  const [data, setData] = useState([]);

  useEffect(() => {
    async function fetchData() {
      const response = await fetch("https://jsonplaceholder.typicode.com/users");
      const result = await response.json();
      setData(result);
    }
    fetchData();
  }, []);

  return (
    <ul>
      {data.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

export default FetchDataExample;

配列の第二引数である[]に依存関係を指定することで、コンポーネントの初回レンダリング後に1回だけAPIを呼び出すようにできます。 また、依存配列に特定のstateを指定すると、その値が変わるたびに副作用を再度実行する仕組みにもできます。

useMemo

useMemoは、メモ化された値を返すHooksです。 ある値の計算結果が重い処理を含む場合に、依存関係が変わらない限り再計算を行わないようにできます。 よく使われるシーンとして、計算コストの高いロジックが複数回走るのを防ぎたい場合などが挙げられます。

import React, { useState, useMemo } from "react";

function HeavyCalculationExample() {
  const [num, setNum] = useState(0);

  const heavyResult = useMemo(() => {
    // ここで重い処理をシミュレート
    let total = 0;
    for (let i = 0; i < 10000000; i++) {
      total += i;
    }
    return total + num;
  }, [num]);

  return (
    <div>
      <p>重い計算の結果: {heavyResult}</p>
      <button onClick={() => setNum(num + 1)}>数値を更新</button>
    </div>
  );
}

export default HeavyCalculationExample;

numが更新されたときのみ再計算されるため、他のstateが変化しても不要な計算を回避できます。

実務での活用シーン

実務においては、フォームや一覧表示などの状態管理は頻繁に登場しますね。 Hooksを使うと、メンテナンス性を保ちながら複雑なロジックを細かく分割しやすくなるでしょう。 特にUIが動的に変化する場面では、状態管理と副作用を切り離して考えられる点が強みです。

状態管理が容易になるケース

例えばECサイトで商品をカートに追加する処理を考えてみてください。 カートの中身という状態はページをまたぐケースもありますが、コンポーネントの階層が深くなると一元的に管理する必要が出てきます。 Hooksを活用すると、複数の状態を独立したuseStateで管理したり、あるいは別のファイルでカスタムHookを定義して読み込むなど、ロジックを整理しやすくなります。

コンポーネント設計がシンプルになる場面

Hooksでは複数の副作用を1つのコンポーネントに詰め込むのではなく、用途ごとに分けて書きやすいのが特徴です。 たとえばAPIデータの取得とWebSocketのリスナー登録を、一つのクラスコンポーネントのライフサイクルメソッドにゴチャゴチャ書くのは大変ですよね。 Hooksを用いればuseEffectを複数回呼び出し、処理内容を分離できるため、可読性の向上が見込まれます。

具体的な例

ここでは、フォームの入力値を管理し、入力内容に応じてリアルタイムに文字数を表示する簡単な例を考えてみましょう。 特別なライブラリを導入しなくてもHooksだけで状態管理と表示を完結できます。

import React, { useState, useEffect } from "react";

function TextInputExample() {
  const [text, setText] = useState("");
  const [charCount, setCharCount] = useState(0);

  useEffect(() => {
    setCharCount(text.length);
  }, [text]);

  const handleChange = (e) => {
    setText(e.target.value);
  };

  return (
    <div>
      <input
        type="text"
        value={text}
        onChange={handleChange}
        placeholder="テキストを入力してください"
      />
      <p>文字数: {charCount}</p>
    </div>
  );
}

export default TextInputExample;

テキストが入力されるたびにuseEffectが発火し、文字数を更新しています。 もし、文字数カウント以外にも別の処理が必要になった場合は、新たに別のuseEffectを追加するだけで分割可能です。 こうすることで、ロジックを機能ごとに整理しやすくなります。

Hooks利用時の注意点

Hooksを使う上で意識しておきたいのが、呼び出しルールです。 Hooksはコンポーネントの最上位レベルで呼び出し、ループや条件分岐の中で実行してはいけないことになっています。 また、カスタムHookを作る場合は関数名を"use"で始めるなど、Reactが勧めるパターンに従うと混乱が生じにくいでしょう。

Hooksの呼び出し順序が変化すると、状態の関連付けが崩れて意図しない挙動を招く場合があります。 コンポーネントの先頭から順番にHooksを並べていく書き方を心がけるのがおすすめです。

さらに、useEffectを多用しすぎて処理が散らばると、逆に読みづらくなることもあります。 行いたい処理をグルーピングしながら適度にカスタムHookへ切り出すといった工夫をすることで、メンテナンスしやすいコードになるはずです。

まとめ

React Hooksは、関数コンポーネントでも状態管理や副作用の処理をシンプルに表現できる手段として、多くのプロジェクトで活用されています。 コンポーネントが増えていくときでも、機能ごとにロジックを切り分けやすくなる点が大きな魅力でしょう。 実務ではフォーム管理やAPIデータの取得、イベントリスナーの管理など、幅広い場面でHooksが使われています。 皆さんも基本的なHooksの使い方を押さえながら、シンプルかつわかりやすいコードの書き方を目指してみるのはいかがでしょうか。

Reactをマスターしよう

この記事で学んだReactの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。