ReactのカスタムフックuseToggle:開閉状態を再利用する
useStateを独自Hookにまとめ、開閉・明示的な開く/閉じる操作と、呼び出しごとの状態の独立性を学びます。
useStateを独自Hookにまとめ、開閉・明示的な開く/閉じる操作と、呼び出しごとの状態の独立性を学びます。
useToggleの役割
開く・閉じる操作をまとめる
useToggle は、真偽値を反転する toggle と、明示的に変更する open・close を返す自作カスタムフックです。Reactに同名の組み込みAPIがあるわけではありません。メニュー、説明欄、フィルターの展開などで利用できます。
カスタムフックは use と大文字で始まる名前にし、ReactのHookを内部で呼びます。呼び出す場所はコンポーネントまたは別のHookのトップレベルです。条件分岐・ループ・イベント関数の内部から呼び出しません。React公式のカスタムフック解説も参照してください。
引数・戻り値と実装
src/hooks/useToggle.ts
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
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で解説します。
Googleの優先するニュース提供元にSEの部屋を追加
Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。
候補にSEの部屋が表示されない場合は、まだ追加できません。