• トップ
  • ブログ一覧
  • Next.jsのParallel Routesを触ってみた
  • Next.jsのParallel Routesを触ってみた

    はじめに

    こんにちは武田です。
    最近Next.jsに触れる機会があり色々調べていると、「Parallel Routes」という機能があり、面白いなと感じたので書かせていただきます。

    Parallell Routesとは

    Next.js(App Router)のルーティング機能の1つで、フォルダ名に「@」を付けることでこのルーティングを利用することができます。
    この方法で作成されたセグメントは「スロット」と呼ばれ、ページに埋め込まれる部分を担うことになります。
    具体的には、スロットは親階層にあるレイアウトに組み込まれ、propsとして渡されるようになります。

    文字だけだとイメージしづらいので、以下を見てください。

    /dashboardディレクトリの下には、@から始まる3つのフォルダが用意されています。
    これらがスロットで、自身から見て親のlayout.tsxにpropsとして渡されます。
    そのため、渡されたスロットを使ってページのレイアウトを組み立てることができます。

    URLには影響しない

    Parallel Routesの特徴として、これはルートセグメントではないため、「@フォルダ名」で作成された部分はURLに反映されません。
    なので、画像の例ですと/dashboard/@overviewにアクセスしても404が返ります。
    ※app/not-found.tsxというファイルで404のときのページを用意してます。

    メリット

    ここまでParallel Routeの概要を見てきましたが、これを使うメリットは何なのでしょうか。
    それは大きく2つあります。
    1. 独立したレンダリング
    2. スロットごとのナビゲーション

    以降ではParallel Routesを使ったダッシュボードっぽいUIを作って見ていきます。

    このようなレイアウトの画面を用意しました。
    色のついたところが各スロット部分で、その中のグレー枠がチャートやグラフ部分だと仮定したものです。

    独立したレンダリング

    まず1つめの利点として、スロットごとに独立したレンダリングを簡単に実装できる点があります。
    これ自体は他の方法でも実現できるものではありますが、Parallel Routesなら「@スロット名」のフォルダを作ってその中にページを作るだけなのでとてもシンプルです。

    独立したレンダリングを検証するために、@activityLogスロットで提供されるページに細工をします。

    1// app/dashboard/@activityLog/page.tsx
    2import Section from "../components/section"; // スロットの枠となるコンポーネント
    3
    4export default async function ActivityLog() {
    5  const title = "ActivityLog";
    6  const style = "h-full bg-blue-100";
    7  await new Promise(() => {}); // 永遠に解決しないPromise
    8  return
    1;
    2}

    そして、@activityLogディレクトリの下に、loading.tsxを作成します。

    1
    2// app/dashboard/@activityLog/loading.tsx
    3export default function Loading() {
    4  return  <div>Analytics slot is loading... </div>;
    5}

    この状態でページを読み込んでみると...

    まだレンダリングが完了していないActivityLogのセクションだけ読み込み中になりました。
    つまり、各スロットは独自にレンダリングされていることがわかります。

    実際のケースですと、表示したい項目によっては重たい処理も入ることもあると思いますが、その部分だけ遅らせて表示することで、他の画面を先に見ることができます。

    スロットごとのナビゲーションについて

    例えば、特定のスロットを別の表示にしたい場合、Parallel Routeを使うと簡単に実現できます。
    Parallel Routeで作成した画面から、同じルート内の別のURLに遷移した場合、その遷移方法によって挙動が変わります。

    1. UI上での遷移

    例えばリンクをクリックして遷移した場合だと、他のスロット部分は以前の状態を保持してくれるので、そのまま表示されます。

    Overviewのセクションにarchiveというリンクを作成しました。
    これは@overview/archived/page.tsxへのリンクです。
    このリンクをクリックすると以下のようになります。

    Overviewのセクションが、ArchivedOverviewになり、URLも/dashboard/archivedになっています。
    ですが、他のセクションは遷移前の状態で表示されています。

    このように、UI上で遷移した場合は他のセクションに影響なく切り替えることができます。

    2. ページリロード

    一方で、アドレスバーにて/dashboard/archivedを直叩きした場合や、リロードした場合は挙動がことなります。

    試しにアドレスバーにて/dashboard/archivedを入力して遷移してみると、404エラーページに遷移しました。
    このようにUI外での遷移では、他のセクションも再読み込みされるので存在しないページへのアクセスとみなされてしまいます。

    ページリロードで404になるのを防ぐ

    方法の1つとして、各階層にdefault.tsxを用意してあげることで404になるのを防げます。
    具体的には以下です。
    - dashboard/
    - 各@スロット/

    default.tsxに表示させる内容は自由なのですが、今回のように/archivedに遷移してもアーカイブが無いページは変わらない内容にしたい場合は、
    page.tsxと同じ内容にしてあげるとリロードにも対応できるページになります。

    1// app/dashboard/default.tsx
    2export default function DefaultDashboardPage() {
    3  return <p>DefaultDashboard</p>;
    4}
    1// app/dashboard/@archive/default.tsx
    2import Section from "../components/section"; // スロットの枠となるコンポーネント
    3
    4export default async function DefaultActivityLog() {
    5  const title = "DefaultActivityLog";
    6  const style = "h-full bg-blue-100";
    7  return <Section title={title} style={style} /gt;;
    8}

    おわり

    今回はParallel Routesについて見ていきました。
    Vue.jsでも出てきたスロットという概念ですが、こちらの方がより構造的かつ直感的で実装しやすい印象でした。
    1画面で複数の役割を持った情報を表示したい時にこの機能を使ってみようと思います。

    参考:
    - https://ja.next-community-docs.dev/docs/app/building-your-application/routing/parallel-routes
    - https://www.builder.io/blog/nextjs-14-parallel-routes

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    たけちゃん(エンジニア)
    たけちゃん(エンジニア)
    Show more...

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background