💬

Hooksがトップレベルでしか呼び出せない理由

2024/06/25に公開

はじめに

かねてから疑問に思っていた、「Hooksがトップレベルでしか呼び出せない理由」について、Udemyで解説してくれており、非常に興味深かったので共有いたします。
Reactの原理原則を図解を用いてわかりやすく解説してくれる良い教材です。この記事では、その内容を参考にしつつ、Hooksがトップレベルでしか呼び出せない理由について詳しく解説します。

Hooksがトップレベルでしか呼び出せない理由

簡単に言うと、Hooksが正しく機能するためには、コンポーネントのレンダリングが行われるたびに同じ順序で呼び出される必要があるからです。トップレベルで呼び出さなければ、この順序が保証されません。

公式ドキュメントでは次のように説明されています。

React内に「メモリーセル」のリストが存在しています。それらは単に何らかのデータを保存できる JavaScript のオブジェクトです。あなたが useState() のようなフックを呼ぶと、フックは現在のセルの値を読み出し(あるいは初回レンダー時はセル内容を初期化し)、ポインタを次に進めます。これが複数の useState() の呼び出しが個別のローカル state を得る仕組みです。

つまり、React内(Fiber)にはhooks用の連結リストが存在しており、同じ順序で呼び出されないとポインタが途切れるため、Hooksがトップレベルでしか呼び出せないのです。

具体例

以下のようなコードを書くと、Reactの内部で管理されているHooksのリストは以下のようになります。
「State1」 → 「State2」 → 「Effect」

  const [state1, setState1] = useState(1);

  // ルール違反:条件付きでフックを使用
  if (state1 > 0) {
    const [state2, setState2] = useState(0);
  }

  useEffect(() => {
    console.log("Hello World!");
  }, []);

state1の値を0以下にした場合、State2が呼ばれません。
つまり、State1はもはや存在しないhooksにリンクしており、Effectへのリンクを持つhooksが消えることになります。

そのため、hooksが一つリストから消えると、リストの順番が完全に崩れてしまいます。
結果として、Reactは使用されたすべてのhooksを正しく追跡できなくなります。

参考

https://ja.react.dev/reference/rules/rules-of-hooks
https://ja.legacy.reactjs.org/docs/hooks-rules.html
https://stackoverflow.com/questions/62805385/why-call-react-hooks-at-the-top-level

Discussion