Open9
Next.js - Parallel Routesで条件に応じてServer Componentsを実行しないようにしたい
最近、とある詳細情報と、さらにその詳細情報に関連した情報をタブ分けしたUIの詳細画面を、Parallel Routesを使って実装しようと試みている。
---------------------------------------------
何かの詳細情報
---------------------------------------------
| Tab A | Tab B | Tab C |
| コンテンツはタブ選択した際に取得したい |
---------------------------------------------
ディレクトリ構成は以下
- app
- list
- [id]
- page.tsx
- layout.tsx
- @a
- page.tsx
- @b
- page.tsx
- @c
- page.tsx
layout.tsx
を以下のように実装することで、タブのコンテンツを出し分けることはできた。
ちなみに、タブの選択状態を query string に持たせるようにしたので、layout.tsx でuseSearchParams
を使わないといけなかった。そのため'use client'
を付与している。
layout.tsx
'use client';
export default function Layout({
children,
a,
b,
}: {
children: React.ReactNode;
a?: React.ReactNode;
b?: React.ReactNode;
c?: React.ReactNode;
}) {
const searchParams = useSearchParams();
const tab = searchParams.get('tab') ?? 'a';
return (
<>
{children}
<Tabs
selectedTab={tab}
/>
<TabPanel>
{match(tab)
.with('a', () => a)
.with('b', () => b)
.with('c', () => c)
.otherwise(() => false)}
</TabPanel>
</>
);
}
表示の切り替えは実現できたものの、tab a, b, c, の page.tsx
自体は実行されてしまっており、表示しないタブの情報を無駄に取得してしまっていることがわかった。
その後は試していないが、おそらく以下のように、自分のタブが選択されているかどうかをチェックすれば、防げるはず。
export default async function PageA({ searchParams }) {
const tab = searchParams?.tab ?? 'a';
if (tab !== 'a') return;
// awesome api call
return <PageAComponent />
}
ただし、どのタブが選択されているかを複数箇所(layout.tsxと、各tab a, b, cのpage.tsx)でチェックしなければいけないので、イマイチ。
公式ドキュメントでは、@loginと@dashboardのParallel Routesを例にしたユースケースが挙げられていたけれど、@dashboardのpage.tsxは、ログインしているしていないに関わらず実行されていそう。
果たしてどうか。
今回の場合、結局、詳細画面のpage.tsxでtabの出し分けを制御する方法に落ち着いたし、こちらの方がシンプルだった。
// 詳細画面のpage.tsx
export default async function Page({ searchParams }) {
const tab = searchParams.'tab' ?? 'a';
return (
<>
<PageDeital />
<Tabs
selectedTab={tab}
/>
<TabPanel>
<Suspense fallback={<Loading />}>
{match(tab)
.with('a', () => <TabA />)
.with('b', () => <TabB />)
.with('c', () => <TabC />)
.otherwise(() => false)}
</Suspense>
</TabPanel>
</>
);
}
// TabAのServer Component
export async function TabA() {
// awesome api call
return <TabAComponent />
}
ということで、Parallel Routesは条件分岐で出し分けするようなケースには適していなさそう、という一旦の結論。
自分の使い方が間違っている可能性もあるので、もう少し追ってみる。