App Router に入門してみる


こんにちは、上條(mk-0A0)です。
Next.js で App Router が使えるようになってからしばらく経ちました。ですが、まだ案件で採用した実績がなく私個人としても触ったことがありませんでした。なので新規案件で採用することになったときの心構えとして、主に Pages Router から変わったところに焦点を充てて今回の記事にしたいと思います。

App Router とは

Next.js v13 で登場した App Router とは何者なのか、公式には以下のように記載があります。

The App Router is a newer router that allows you to use React’s latest features, such as Server Components and Streaming.

App Router は、Server Components や Streaming といった React の最新機能を利用できる、より新しいルーターです。(deepL 日本語訳)

App Router vs Pages Router | Next.js

Server Components” “Streaming” という単語が出てきました。これらは React の最新機能で、使うことでレンダリングの時間が短縮されパフォーマンスの向上につながると理解しています。詳しくは後述します。

変わったところ

では Pages Router から何が変わったのか、3つピックアップして簡単に解説します。

ファイル構成

まず大きく変わったのはファイル構成です。Pages Router では src/pages/XXX/index.tsx にページを作っていましたが、App Router では app/XXX/page.tsx となります。
そして各ディレクトリには共通レイアウトのファイルを置くことができます。共通レイアウトとは、ページ共通のレイアウトを定義する layout.tsx 、ローディングを表示する loading.tsx 、エラーを表示する error.tsx などです。これらは共通レイアウトが置かれているディレクトリ配下のページすべてに適用されます。

以下はヘッダーとフッターを定義した app/layout.tsx を作成したサンプルです。どのページにアクセスしても同じレイアウトが表示されています。

こちらは新しく app/about/layout.tsx を作成したサンプルです。/about にアクセスするとレイアウトが上記のサンプルと変わっています。このように、pages.tsx は自身から一番近い共通レイアウトのファイルを読み込むようにできています。

Routing: Pages and Layouts | Next.js

データフェッチの方法

Pages Router では、データフェッチに getServerSidePropsgetStaticProps を使っていました。
App Router ではそれらがサポートされておらず、ブラウザ API である fetch を使って関数を定義することでデータをフェッチします。また fetch を使うことで重複したリクエストを自動的に排除してくれるので、その分パフォーマンスも改善されるようです。
以下は Next.js 公式のサンプルコードです。

async function getData() {
  const res = await fetch('https://api.example.com/...')
  // The return value is *not* serialized
  // You can return Date, Map, Set, etc.
 
  if (!res.ok) {
    // This will activate the closest `error.js` Error Boundary
    throw new Error('Failed to fetch data')
  }
 
  return res.json()
}
 
export default async function Page() {
  const data = await getData()
 
  return <main></main>
}

Data Fetching, Caching, and Revalidating | Next.js

Server Component ベース

先程少し触れましたが、App Router は Server Component をベースとしています。パフォーマンスの向上はメリットと捉えられますが、Server Component はクライアントで実行される Hooks や イベントハンドラーが使えないなどのデメリットもあります。このような処理をするには Client Component として扱う必要があり、ファイルに 'use client' と記載することで使用できるようになります。ちなみに、'use client' を宣言したファイルで呼び出されるコンポーネントは自動的に宣言が無くても Client Component 扱いとなります。
以下は Next.js 公式のサンプルコードです。

'use client'
 
import { useState } from 'react'
 
export default function Counter() {
  const [count, setCount] = useState(0)
 
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}

Client Components | Next.js

参考資料

Next.js 13 app directory で記事投稿サイトを作ってみよう
App Router | Next.js
Server Components | Next.js

まとめ

App Router だけでなく Server Component についても触れる機会がなかったので、これを機に深掘りできるともっと理解が深まると思いました。まだあまり理解できていない Pages Router との使い分けにも関わってくると思うので、それを理解できるようになるためにも引き続き勉強を進めます。


投稿者 Kamijo Momoka

フロントエンドエンジニア。
HTML/CSS/JavaScript/WordPressでのサイト制作からNext.js/TypeScriptなどを使ったWebアプリ開発、FigmaでのUIデザインまで広く経験しています。 デザインエンジニアと名乗るのが夢です。