🦔

layout.tsxに"use client"を指定したのに、そこを経由するpage.tsxでフックが使えないのはなぜ?

に公開

前提

  • Geminiと壁打ちしてわかったことなので、内容は間違えているかもしれません
  • 間違えていたら教えていただけると嬉しいです🙏

疑問が生まれた

前提、Next.jsにはこんな機能がある

  • Next.jsには以下の機能がある
    • デフォルトはサーバーサイドコンポーネントだよ
    • "use client"をファイルの頭につけるとクライアントコンポーネントになるよ
    • そのコンポーネントの子供にあたるコンポーネントは、"use client"をつけなくてもクライアントコンポーネントになるよ
"use client"; // これがあると、UserItemもクライアントコンポーネントとする
import { UserItem } from "../_components/UserItem";

export default function UsersPage() {
  return (
    <div>     
      <UserItem />
    </div>
  );
}

ということは?

  • ってことはlayout.tsxとpage.tsxも同じ話だよね
    • 同じディレクトリ内にlayout.tsxとpage.tsxがある場合
      • layout.tsxをクライアントコンポーネントにすれば、page.tsxもクライアントコンポーネントになるから、useEffectとか使えるよね

結果

useEffect使えない。エラーになった。なんでや。

Geminiと壁打ちしてわかったことまとめ

訳わからなすぎて1時間くらい壁打ちしてた。
結論わかったこと。

なぜlayout.tsxに"use client"を指定してもエラーになるのか

  • 結論、page.tsxに"use client"がないと、ビルド時にサーバーコンポーネントと認識される
    • なのでuseEffectとかでエラーになる

図にするとこんな感じ

つまり、page.tsxは普通にサーバーサイドコンポーネントとして処理されたのち、出来上がった結果がアントコンポーネントであるlayout.tsxの子要素に挿入される。

layout.tsxの子がpage.tsxであるという解釈が間違えていた

  • page.tsxは単体でビルドされる
    • デフォルトはサーバーコンポーネント、use clientが指定されていればクライアントコンポーネントとして扱われる
  • その処理結果が、layout.tsxに渡る

→ なので、layout.tsxがクライアントコンポーネントだからといって、その下部でレンダリングされる予定のpage.tsxもクライアントコンポーネントになるわけではない。

  • page.tsxでuseEffectなどをを使いたい場合
    • 経由するlayout.tsxに"use client"があっても、page.tsxに記述がないとビルドエラー
    • ビルド時のチェックを抜けるためにpage.tsxにも"use client"を書く必要ある

感想

頭おかしくなりそうだった🚗

Discussion