1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React Hooks入門②

1
Last updated at Posted at 2026-06-02

💡はじめに

Reactでは「Hooks」を使用することで、状態管理やライフサイクル処理などを関数コンポーネント内で簡単に実装できます。
Hooksを理解することで、Reactの動きやコンポーネントの仕組みを理解しやすくなります。

この記事では、Reactでよく使用されるHooksについて、簡単なサンプルコードを交えながら紹介していきます。

できるだけシンプルにまとめているので、React学習中の方の参考になれば幸いです。

✈️関連記事はこちら
React Hooks入門①
React Hooks入門③

👍こんな人におすすめ

・最近Reactを勉強し始めた
・Reactをもう少し理解したい
・使用経験のないHooksを理解したい
・さくっと学びたい

🚩React Hooks

目次

8.Custom Hook
9.useLayoutEffect
10.useImperativeHandle
11.useId
12.useTransition
13.useDeferredValue
14.useSyncExternalStore

8.Custom Hook

Custom Hookは、複数のコンポーネントで共通利用したい処理をまとめるための機能です。
Reactでは、Hookを組み合わせて独自のHookを作成できます。
同じ処理を何度も書かなくてよくなるため、コードの再利用性を高められます。
ただし、複数のコンポーネントで呼び出した場合、それぞれ独立したstateを持ちます。
同じ状態を共有したい場合は、useContextや外部ストアなどを組み合わせます。

useCounter.jsx
import { useState } from 'react';

const useCounter = () => {

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

  const increment = () => {
    setCount((prev) => prev + 1);
  };

  const decrement = () => {
    setCount((prev) => prev - 1);
  };

  return {
    count,
    increment,
    decrement
  };
};

export default useCounter;
App.jsx
import './App.css';
import useCounter from './useCounter';

function App() {

  const { count, increment, decrement } = useCounter();

  return (
    <div>
      <h1>customHook</h1>

      <p>count:{count}</p>

      <button onClick={increment}>
        +1
      </button>

      <button onClick={decrement}>
        -1
      </button>
    </div>
  );
}

export default App;

customHookは通常の関数と同じように作成できます。
ただし、ReactのHookであることを分かりやすくするため、useから始める命名ルールがあります。

const useCounter = () => {

今回のサンプルでは、カウント機能をuseCounterにまとめています。
コンポーネント側では、Hookを呼び出すだけで状態管理の処理を利用できます。

const { count, increment, decrement } = useCounter();

例えば以下のような場面で利用されます。

・API通信処理
・フォーム管理
・認証処理
・共通状態管理

同じ処理を複数のコンポーネントで使いたい場合によく利用されます。

9.useLayoutEffect

useLayoutEffectは、画面描画前に処理を実行できるHookです。

基本的な使い方はuseEffectと似ていますが、実行されるタイミングが異なります。

・useEffect
→画面描画後に実行
・useLayoutEffect
→DOMの更新後、ブラウザが画面に描画する前に実行

DOMサイズの取得やレイアウト調整などで利用されます。

import { useLayoutEffect, useRef } from 'react';
import './App.css';

function App() {

  const boxRef = useRef(null);

  useLayoutEffect(() => {

    // 要素の横幅を取得
    const width = boxRef.current.offsetWidth;

    console.log(`横幅:${width}px`);

  }, []);

  return (
    <div>
      <h1>useLayoutEffect</h1>

      <div
        ref={boxRef}
        style={{
          width: '300px',
          padding: '20px',
          backgroundColor: '#ddd'
        }}
      >
        サンプル要素
      </div>
    </div>
  );
}

export default App;

useLayoutEffectは以下のように記述します。

useLayoutEffect(() => {

  実行したい処理

}, []);

今回の場合は、コンポーネント表示時にDOM要素の横幅を取得しています。

const width = boxRef.current.offsetWidth;

useLayoutEffectは画面描画前に実行されるため、DOMサイズ取得やレイアウト調整を行いたい場合に利用されます。
例えば以下のような場面で利用されます。

・DOMサイズ取得
・スクロール位置調整
・アニメーション制御
・レイアウト調整

通常はuseEffectを使用し、DOM描画前に処理したい場合のみuseLayoutEffectを使用します。

10.useImperativeHandle

useImperativeHandleは、親コンポーネントから子コンポーネントの関数や値を操作できるようにするHookです。

useImperativeHandleは便利ですが、親から子を直接操作するため、使いすぎるとコンポーネント間の結合が強くなります。
通常はpropsで制御し、inputのfocus制御や動画再生制御など、命令的な操作が必要な場合に利用します。

App.jsx
import { useRef } from 'react';
import './App.css';
import CustomInput from './CustomInput';

function App() {

  const inputRef = useRef(null);

  // 子コンポーネントの関数を実行
  const handleClick = () => {
    inputRef.current?.focusInput();
  };

  return (
    <div>
      <h1>useImperativeHandle</h1>

      <CustomInput ref={inputRef} />

      <br /><br />

      <button onClick={handleClick}>
        フォーカス
      </button>
    </div>
  );
}

export default App;
CustomInput.jsx
import {
  forwardRef,
  useImperativeHandle,
  useRef
} from 'react';

const CustomInput = forwardRef((props, ref) => {

  const inputRef = useRef(null);

  // 親コンポーネントへ公開する処理
  useImperativeHandle(ref, () => ({
    focusInput() {
      inputRef.current?.focus();
    }
  }));

  return (
    <input
      type="text"
      ref={inputRef}
    />
  );
});

export default CustomInput;

useImperativeHandleは以下のように記述します。

useImperativeHandle(ref, () => ({
  公開したい処理
}));

今回の場合は、focusInput()を親コンポーネント側へ公開しています。

focusInput() {
  inputRef.current?.focus();
}

親コンポーネントではrefを使用することで、子コンポーネントの関数を実行できます。

inputRef.current?.focusInput();

例えば以下のような場面で利用されます。

・inputのフォーカス制御
・モーダル操作
・動画再生制御
・子コンポーネントの関数実行

親コンポーネントから子コンポーネントを直接操作したい場合に利用されるHookです。

11.useId

useIdは、一意なIDを生成できるHookです。
配列をmapで表示する際のkeyとしては使用しません。
keyにはデータが持つIDなど、要素を一意に識別できる値を使用します。
useIdはSSRでも安定したIDを生成できるため、サーバー側とクライアント側でIDがずれる問題を防ぎやすくなります。

import { useId } from 'react';
import './App.css';

function App() {

  // 一意なIDを生成
  const id = useId();

  return (
    <div>
      <h1>useId</h1>

      <label htmlFor={id}>
        ユーザー名
      </label>

      <br />

      <input
        id={id}
        type="text"
      />
    </div>
  );
}

export default App;

useId()を使用することで、一意なIDを生成できます。

const id = useId();

生成したIDをlabelとinputに設定することで、関連付けが行えます。

<label htmlFor={id}>
<input id={id} />

今回の場合、labelをクリックするとinputへフォーカスが移動します。

例えば以下のような場面で利用されます。

・フォーム部品のID生成
・labelとinputの関連付け
・アクセシビリティ対応
・重複しないID管理

フォーム部品を扱う場合によく利用されるHookです。

12.useTransition

useTransitionは、優先度の低い更新処理を後回しにできるHookです。
startTransitionは、内部のstate更新を優先度の低い更新として扱います。
ただし、startTransition内に書いた重いJavaScript処理そのものが別スレッドで実行されるわけではありません。
重い計算処理自体を軽くしたい場合は、useMemo、仮想スクロール、Web Workerなども検討します。

import { useMemo, useState, useTransition } from 'react';
import './App.css';

function App() {
  const [text, setText] = useState('');
  const [query, setQuery] = useState('');

  const [isPending, startTransition] = useTransition();

  const list = useMemo(() => {
    const items = [];

    for (let i = 0; i < 20000; i++) {
      items.push(`${query}-${i}`);
    }

    return items;
  }, [query]);

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

    // 入力欄の更新は優先度高く更新
    setText(value);

    // リスト更新は優先度を下げる
    startTransition(() => {
      setQuery(value);
    });
  };

  return (
    <div>
      <h1>useTransition</h1>

      <input
        type="text"
        value={text}
        onChange={handleChange}
      />

      {isPending && <p>更新中...</p>}

      <ul>
        {list.map((item) => (
          <li key={item}>
            {item}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

useTransitionは以下のように記述します。

const [isPending, startTransition] = useTransition();
名前 内容
isPending 処理中かどうか  
startTransition 優先度を下げて実行する関数

例えば以下のような場面で利用されます。

・検索機能
・大量データ表示
・フィルタ処理
・パフォーマンス改善

重い処理で画面操作が遅くなる場合に利用されるHookです。

13.useDeferredValue

useDeferredValueは、値の更新の優先度を下げ、Reactが余裕のあるタイミングで反映できるようにするHookです。
debounceやsetTimeoutのように、指定した時間だけ遅らせるHookではありません。
Reactが緊急度の高い更新を優先し、余裕のあるタイミングで遅延した値を更新します。

import {
  useDeferredValue,
  useMemo,
  useState
} from 'react';

import './App.css';

function App() {

  const [text, setText] = useState('');

  // 更新を遅延
  const deferredText = useDeferredValue(text);

  // 遅延した値でリスト生成
  const list = useMemo(() => {

    const items = [];

    for (let i = 0; i < 20000; i++) {
      items.push(deferredText);
    }

    return items;

  }, [deferredText]);

  return (
    <div>
      <h1>useDeferredValue</h1>

      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
      />

      <ul>
        {list.map((item, index) => (
          <li key={index}>
            {item}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

useDeferredValue()を使用することで、値の更新タイミングを遅らせられます。

const deferredText = useDeferredValue(text);

今回の場合は、入力値textをそのまま使用せず、遅延したdeferredTextを利用しています。

const list = useMemo(() => {

  const items = [];

  for (let i = 0; i < 20000; i++) {
    items.push(deferredText);
  }

  return items;

}, [deferredText]);

これにより、input入力を優先しながら重い描画処理を実行できます。

例えば以下のような場面で利用されます。

・検索機能
・大量データ表示
・リアルタイムフィルタ
・パフォーマンス改善

入力操作をスムーズに保ちながら重い処理を実行したい場合に利用されるHookです。

14.useSyncExternalStore

useSyncExternalStoreは、外部ストアの状態をReactと同期するためのHookです。
Reduxや独自ストアなど、React外で管理しているデータを安全に取得したい場合に利用されます。

App.jsx
import { useSyncExternalStore } from 'react';

import {
  getSnapshot,
  increment,
  subscribe
} from './store';

import './App.css';

function App() {

  // 外部ストアと同期
  const count = useSyncExternalStore(
    subscribe,
    getSnapshot
  );

  return (
    <div>
      <h1>useSyncExternalStore</h1>

      <p>count:{count}</p>

      <button onClick={increment}>
        カウントアップ
      </button>
    </div>
  );
}

export default App;
store.js
let count = 0;

// 購読リスト
let listeners = [];

// count取得
export const getSnapshot = () => {
  return count;
};

// count更新
export const increment = () => {

  count++;

  listeners.forEach((listener) => listener());
};

// 購読
export const subscribe = (listener) => {

  listeners.push(listener);

  return () => {
    listeners = listeners.filter((l) => l !== listener);
  };
};

useSyncExternalStoreは以下のように記述します。

useSyncExternalStore(
  subscribe,
  getSnapshot
);
引数 内容
subscribe 状態変更の監視  
getSnapshot 現在の状態取得

今回の場合は、外部ストアのcountをReactコンポーネントへ同期しています。

const count = useSyncExternalStore(
  subscribe,
  getSnapshot
);

ボタンをクリックすると外部ストア側のcountが更新され、React側の画面も自動更新されます。

例えば以下のような場面で利用されます。

・Redux連携
・グローバル状態管理
・外部ストア同期
・リアルタイムデータ管理

React外で管理している状態を扱う場合に利用されるHookです。


✈️関連記事
React Hooks入門①

React Hooks入門③

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?