[React] Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.

エラー文

Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.

意味

Hooksを定義する際、条件分岐等の他の値を返す可能性のある処理の後に定義すると発生するエラーです。

Bad

useState() 等の標準Hooksを使った例は記事が色々あるため、少し特殊な例です。

export function useHoge() {
  // 条件 (例えばどのページを表示しているか) によって処理を分けるカスタムフック
  const { switchProps } = useSwitchProps()

  // useDataStoreSelectorは、データを保持するストア
  // ページによって呼び出すストア(カスタムフック)を変えている
  const props = useMemo(() => {
    return switchProps({
      page1: useDataStoreSelector1(),
      page2: useDataStoreSelector2(),
    })
  }, [])
}

この例では、switchProps内で条件分岐でページによって呼び出すHooksを変えている。
カスタムフックのルールとして、条件分岐後に定義してはならない(返す値が一定でなくなるため)というものがあり、そのルールに抵触するため、エラーとなる。

Good

条件分岐の前に、カスタムフックを宣言すれば良い。

export function useHoge() {
  // 条件 (例えばどのページを表示しているか) によって処理を分けるHooks
  const { switchProps } = useSwitchProps()

  // 条件分岐の前にストアからデータを取得
  const data1 = useDataStoreSelector1()
  const data2 = useDataStoreSelector2()

  // 事前に取得したデータを渡す
  const props = useMemo(() => {
    return switchProps({
      page1: data1,
      page2: data2,
    })
  }, [page1, page2]) // ストアの値が変わったら返却するデータが変わる可能性があるため、依存パラメータに指定しておく
}

参考