AppRouterのグループ化したlayout単位で共通の処理をする
開発環境
- next 13.4.10
前提
Next.jsのv13.4からStableになったAppRouterを利用します。
また、本記事ではAppRouterのlayoutに焦点を当てています。
本題
AppRouterになってから色々な機能が追加され、まだまだ触りきれていない今日この頃です。
ところで、認証機能があるアプリケーションでは認証か必要なページ、必要ないページの2パターンがあることが多いと思います。
そんな時に、認証が必要なページをまとめて処理できると嬉しいです。
今回はAppRouterのlayoutを利用して、共通の認証処理をする一例を紹介します。
これまでのPageRouterでは、ページごとに、例えばServerSideProps内で非認証ユーザーならログインページにリダイレクトする、のような処理をしていたと思います。
AppRouterではルートレイアウト、もしくは認証を行いたいセグメントのルートレイアウトで認証を行うことで、配下のページごとの認証は不要にできます。
以下のディレクトリ構成で考えてみます。
また、ダッシュボードとマイページにのみ認証処理をしたいと仮定します。
実装例の前に、ポイントが3つあります。
- URLに影響を与えず、セグメントをグループ化します。今回のケースだと(auth)、(private)、(public)にあたる部分
- layoutは親から子へ継承していく
- layoutは上位のレイヤーで実行されている
.
└── app
├── layout.tsx ← ルートレイアウト
|
├── (auth)
| ├── layout.tsx ← authグループのルートレイアウト
| ├── login
| | └── page.tsx
| └── signup
| └── page.tsx
|
├── (private)
| ├── layout.tsx ← privateグループのルートレイアウト
| ├── dashboard
| | └── page.tsx
| └── mypage
| └── page.tsx
|
└── (public)
├── layout.tsx ← publicグループのルートレイアウト
└── articles
└── page.tsx
上記の構成例では、以下のようにlayout.tsxを実装すれば配下の各ページが実行される前に、layoutコンポーネントが実行されるので、各ページでの処理は不要になります。
import { redirect } from 'next/navigation';
import type { ReactNode } from 'react';
import { Footer } from '@/components/footer';
import { Header } from '@/components/header';
export default function PrivateLayout({ children }: { children: ReactNode }) {
const isLoggedIn = false; // MEMO: 本来はここで認証を行うためのAPIを叩く想定
if (!isLoggedIn) return redirect('/login');
return (
<>
<Header />
<main>
<h1>PrivateLayout</h1>
{children}
</main>
<Footer />
</>
);
}
補足として、layout.tsxはサーバーコンポーネントになりますが、redirectはサーバーで実行可能なので、こちらを利用してログインページにリダイレクトする処理をしています。
さいごに
AppRouterのシステムを利用しながら実装していくと、これまでとは違う実装をする部分も多々出てきますが、効率よく実装できる方向性に向かっているのかなと感じています。
また、今回紹介していないですが、並行ルートを活用するとより複雑な画面でも柔軟に対応できるみたいなので、この辺りもチェックしていきたいです。