実現したいこと
App routerを用いたnext.jsプロジェクトのRootlayout(サーバサイド)で用いる値(session, pathname)を、ページの遷移毎に更新したい。
発生している問題・分からないこと
page.tsxを読み込んでもlayout.tsxはリロードしないので、値は自動的に更新されません。
RootlayoutではgetServerPropsが使えず、サーバサイドなのでフックも使えないので、それ以外の方法を探しているのですが見つかりません。
(getServerSessionもheadersもプロジェクトの開始時かリロード時に実行されるので、流石に毎回リロードするのはUX的にNGかなと思います。)
該当のソースコード
layout.tsx
1import './globals.css'; 2 3import { Metadata } from 'next'; 4// googleのフォントの一種であるInconsolataをインポートしている 5import { Inconsolata } from 'next/font/google'; 6 7import { headers } from 'next/headers'; 8 9import SignOutMenu from '@/components/SignOutMenu'; 10 11import Link from 'next/link'; 12import Image from 'next/image'; 13 14import { getServerSession } from 'next-auth'; 15import { authOptions } from '@/lib/authOptions'; 16 17const fnt = Inconsolata({ subsets: ['latin']}); 18 19export default async function RootLayout({children,}: Readonly<{ 20 children: React.ReactNode; 21}>) { 22 const session = await getServerSession(authOptions); 23 const pathname = (await headers()).get("x-url") || ''; 24 25 return ( 26 <html lang="ja"> 27 <body className={fnt.className}> 28 <h1 className="text-4xl text-indigo-800 font-bold my-2">Earthlete</h1> 29 <ul className="flex bg-blue-600 mb-4 pl-2"> 30 <li className={`block px-4 py-2 my-1 hover:bg-gray-100 rounded ${pathname === '/' ? "bg-fuchsia-600" : ""}`}> 31 <Link className="no-underline text-blue-300" href="/"> 32 ホーム</Link></li> 33 <li className={`block text-blue-300 px-4 py-2 my-1 hover:bg-gray-100 rounded ${pathname === '/threads' ? "bg-fuchsia-600" : ""}`}> 34 <Link className="no-underline text-blue-300" href="/threads"> 35 掲示板</Link></li> 36 </ul> 37 <ul className="flex fixed top-3 right-2 z-20"> 38 {pathname !== '/logIn' && !session && 39 <li className="block px-3 py-1 my-1 hover:bg-gray-100 rounded"> 40 <Link className="no-underline text-blue-600" href="/signIn"> 41 サインイン</Link></li> 42 } 43 <SignOutMenu pathname={pathname} login={session ? true : false}/> 44 {pathname !== '/addAccount' && !session && 45 <li className="block px-3 py-1 my-1 hover:bg-gray-100 rounded"> 46 <Link className="no-underline text-orange-400" href="/addAccount"> 47 新規登録</Link></li> 48 } 49 {pathname !== '/editProfile' && session && 50 <li className="px-1 py-1 mx-2 rounded-full border"> 51 <Link className="text-blue-300" href="/editProfile"> 52 <Image src='/defaultIcon.png' alt="" width={32} height={32}/> 53 </Link></li> 54 } 55 </ul> 56 <div className="mx-2"> 57 {children} 58 </div> 59 </body> 60 </html> 61 ); 62}
SignOutMenu.tsx
1'use client'; 2 3import Link from 'next/link'; 4 5import { useState } from 'react'; 6 7import { signOut } from 'next-auth/react'; 8import { redirect } from 'next/navigation' 9 10export default function SignOutMenu({ pathname, login } : { pathname: string | null, login: boolean }) { 11 const [showLogoutMenu, setShowLogoutMenu] = useState<boolean>(false); 12 13 const handleLogout = () => { 14 signOut(); 15 setShowLogoutMenu(false); 16 redirect('/'); 17 }; 18 19 return ( 20 <> 21 {showLogoutMenu && 22 <div className="fixed top-0 left-0 bg-gray-300 opacity-50 h-full w-full z-21"></div> 23 } 24 {pathname !== '/logOut' && login && 25 <li className="block px-3 py-1 my-1 hover:bg-gray-100 rounded"> 26 <button className="text-blue-600" onClick={() => setShowLogoutMenu(!showLogoutMenu)}> 27 サインアウト</button></li> 28 } 29 {showLogoutMenu && login && 30 <div className="fixed flex top-0 left-0 justify-center items-center text-center w-full h-screen z-22"> 31 <div className=" border-black border-2 w-3/5 md:w-2/5 lg:w-1/5 h-1/5"> 32 <p className="my-6">ログアウトしますか?</p> 33 <ul className="flex justify-around"> 34 <li><Link className="no-underline text-white bg-blue-600 p-4 rounded" onClick={ () => setShowLogoutMenu(false) } href={pathname || "/"}> 35 キャンセル</Link></li> 36 <li><Link className="no-underline text-white bg-red-600 p-4 rounded" onClick={handleLogout} href="/"> 37 サインアウト</Link></li> 38 </ul> 39 </div> 40 </div> 41 } 42 </> 43 ); 44}
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
上述の通り、getServerPropsを使おうとしても、これはpage.tsxにしか使えないので問題は解決しませんでした。(page.tsxにコンポーネントは配置したくないです。)
補足で、getServerSessionに関してはsignOutした時は再レンダリングされてサインアウト後の状況が反映されているのですが、signInの時はなぜか再レンダリングされずサインイン後の状況が反映されないことが確認できました。
更に補足で、signInのオプションであるredirect: falseを消去したら再レンダリングされてgetServerSessionが反映されるようになりました!!
あとはheaders()の方だけ解決できたらOKです!!
補足
signOutMenuコンポーネントとlayout.tsx内のコンポーネントの背景色や表示/非表示を現在のurl(pathname)とログイン状況(session)で制御しています。
あと、rootlayoutをサーバサイドにすることにこだわっているのは、app routerのメリットを活かすためです。もし、この点を気にしなくても良いと分かれば、rootlayoutはクライアントサイドにしようと思います(https://zenn.dev/h_tatsuru/articles/app_router_pros_and_cons)。

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。