React.js

ReactのカスタムフックuseToggle:開閉状態を再利用する

この記事でわかること

useStateを独自Hookにまとめ、開閉・明示的な開く/閉じる操作と、呼び出しごとの状態の独立性を学びます。

useStateを独自Hookにまとめ、開閉・明示的な開く/閉じる操作と、呼び出しごとの状態の独立性を学びます。

useToggleの役割

開く・閉じる操作をまとめる

useToggle は、真偽値を反転する toggle と、明示的に変更する openclose を返す自作カスタムフックです。Reactに同名の組み込みAPIがあるわけではありません。メニュー、説明欄、フィルターの展開などで利用できます。

カスタムフックは use と大文字で始まる名前にし、ReactのHookを内部で呼びます。呼び出す場所はコンポーネントまたは別のHookのトップレベルです。条件分岐・ループ・イベント関数の内部から呼び出しません。React公式のカスタムフック解説も参照してください。

引数・戻り値と実装

src/hooks/useToggle.ts

TypeScript
import { useState } from 'react';

export function useToggle(initialValue = false) {
  const [isOpen, setIsOpen] = useState(initialValue);
  function toggle() { setIsOpen(current => !current); }
  function open() { setIsOpen(true); }
  function close() { setIsOpen(false); }
  return { isOpen, toggle, open, close };
}

initialValue は初回の初期値です。後で引数が変わってもstateは自動的にはリセットされません。親から常に状態を制御したい場合は、親でstateを持ち、値と変更関数をpropsで渡す設計にします。

toggle は直前のstateを引数にする更新関数を使っています。1つのイベントで連続して更新を予約しても、古い値だけを基準に反転しないためです。open は何度呼んでも開いた状態にし、close は閉じた状態にします。

コンポーネントから使う

src/App.tsx

TSX
import { useId } from 'react';
import { useToggle } from './hooks/useToggle';

export default function App() {
  const { isOpen, toggle, close } = useToggle();
  const panelId = useId();
  return (
    <main>
      <h1>追加の説明</h1>
      <button type="button" onClick={toggle}
        aria-expanded={isOpen} aria-controls={panelId}>
        {isOpen ? '説明を閉じる' : '説明を開く'}
      </button>
      <div id={panelId} hidden={!isOpen}>
        <p>カスタムフックから開閉状態を受け取っています。</p>
        <button type="button" onClick={close}>閉じる</button>
      </div>
    </main>
  );
}

ViteのReact+TypeScript構成で2ファイルを保存します。ボタンの表示と aria-expanded が開閉に追従することを確認してください。この例は説明欄です。モーダルに発展させる場合は、フォーカス管理、Escapeキー、背景の操作制限なども必要になります。

状態の共有と関数の参照

同じHookを呼んでもstateは別々

2つのコンポーネントで useToggle() を呼び出すと、それぞれ独立したstateを持ちます。共通になるのはロジックであり、状態自体ではありません。同じ開閉状態を共有する場合は親で1回呼び、propsやContextで渡します。

useCallbackは必要なときだけ

この実装の関数はレンダーごとに作られます。通常のボタンへ渡すだけなら問題ありません。関数参照の安定性が必要なAPIを設計する場合は useCallback を検討しますが、常に追加すると速くなるものではありません。

動作確認のポイント

開閉を順番に試す

初期状態は閉じる、1回押すと開く、2回押すと閉じることを確認します。useToggle(true) なら最初から開きます。同じHookを使う説明欄を2つ用意し、片方だけ操作して状態が独立していることも確かめます。

APIに伴うstate管理はuseApiDataで解説します。

PREFERRED SOURCES

Googleの優先するニュース提供元にSEの部屋を追加

Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。

Googleの設定画面で確認する 新しいタブで開きます

候補にSEの部屋が表示されない場合は、まだ追加できません。

y.
WRITTEN BY

y_ymo10

SEの部屋で、HTML・CSSからJavaScript・React・Next.jsまで、Web制作の開発ノートを公開しています。

ほかの開発ノートを読む →