Parallel routesとSuspense
はじめに
Parallel routes、すごくいい機能だと思います。ただ、バグが多いということも聞きます。できるだけ新しい機能を使いたいと思い、採用していたのですが、バグっぽい挙動にぶち当たってしまい、今では必ずしも現段階で採用しなくてもいいのでは?と思っています。
本記事ではParallel routesの簡単な紹介と、コンポーネント毎のloadingの表示分けだけで利用するなら、少なくとも現時点では、suspenseでもいいのでは?ということを記載しようと思います。
補足
自分が当てたバグは、Parallel routesをRootLayout.tsxで利用している前提で、最初に'/'ページにアクセスして、それ以下のページにアクセスはできるのですが、例えば'/admin'ページにURL直打ちでアクセスした後、'/'ページに移動すると真っ白な画面しか表示されないというものでした。(Parallel routesをやめると治る)
parallel routes
簡単に言うと、コンポーネントを分割するための便利機能です。
機能概要
- layout.tsx内で利用可能
- テンプレートを作成できる
- それぞれのコンポーネント毎にローディング画面やエラー画面など設定可能
- 条件による出し分けが可能
- ページごとに表示する内容を設定可能
利用方法
以下のようなファイル構成で考えます。
app/
├ layout.tsx
├ page.tsx
├ pageA/
| ├ page.tsx
| └ loading.tsx
├ @componentA/
| ├ page.tsx
| ├ default.tsx
| └ loading.tsx
└ @componentB/
├ page.tsx
├ loading.tsx
└ pageA/
└ page.tsx
以下のように@がついたコンポーネントをlayout.tsxで引数として受け取って利用できます。
例えば、componentA/page.tsxがデータを取得して表示する、時間がかかるコンポーネントであれば、componentAが読み込み中は{props.componentA}の場所はapp/@componentA/loading.tsxで定義したものが表示されます。
export default function Layout(props: {
children: React.ReactNode
componentA: React.ReactNode
componentB: React.ReactNode
}) {
return (
<>
{props.children}
{props.componentA}
{props.componentB}
</>
)
}
default.tsx
先ほどのページにも記載がありますが、配下のページ(今回だとpageA)でもcomponentAとcomponentBを正しく表示するためにはcomponentAのようにdefault.tsxを作成するか、componentBのようにpageA/page.tsxを作成して、pageAにアクセスがあった場合に、componentA・componentBに何を表示するか指定しておく必要があります。
これがないと、404エラーが発生します。
見られる順番としては以下
- componentBのようにページ指定の表示があるか
- componentAのようにdefault.tsxがあるか
- どちらもなければ404エラー
特にページごとに表示を切り替えたいわけでなければ、default.tsxを以下の内容にしましょう。
page.tsxの内容をそのまま返しているだけです。
import Page from './page'
export default async function Default() {
return (
<Page />
)
}
Suspenseでのコンポーネント表示までのローディング表示について
Parallel routesではコンポーネント内にloading.tsxを配置することで、読み込みまでのローディング表示を指定できます。
ただし、Parallel routesを使わなくてもreactのSuspenseを使えば同じことが可能です。
以下のようなファイル構成で考えます。
app/
├ layout.tsx
└ page.tsx
componentA/
├ componentA.tsx
└ loading.tsx
Suspenseのfallbackに指定したものが、Suspenseで囲ったコンポーネントを表示するまでのローディング画面として表示されます。
import { Suspense } from "react";
import Loading from './componentA/loadging'
import ComponentA from './componentA/componentA'
export default function Layout(props: {
children: React.ReactNode
}) {
return (
<>
{props.children}
<Suspense fallback={<Loading />}>
<ComponentA />
</Suspense>
</>
)
}
まとめ
Parallel routesの簡単な紹介と、非同期コンポーネントで利用できるSuspenseを紹介しました。使えれば便利ですが、Parallel routesはバグが多く、Parallel routesじゃないとダメなケースはあまりないので、安定するまではなるべく避けていこうと思います。
Discussion