App Router Incremental Adoption Guide
このガイドはあなたを助けます:
- あなたの Next.js アプリケーションを version 12 から version 13 にアップデート
pages
およびapp
ディレクトリの両方で機能するアップグレード機能- 既存のアプリケーションを
pages
からapp
へ段階的に移行します
Upgrading
Node.js Version
最小の Node.js version は現在v18.17です。詳細については、Node.js ドキュメンテーション をご覧ください。
Next.js Version
あなたの好みのパッケージマネージャーを使用して、Next.js version13 にアップデートするには、次のコマンドを実行してください。
npm install next@latest react@latest react-dom@latest
ESLint Version
あなたが ESLint を使っている場合、あなたの ESLint version をアップグレードする必要があります:
npm install -D eslint-config-next@latest
Good to know: ESLint server の変更が反映されるためには、VS Code で ESLint server を再起動する必要があるかもしれません。コマンドパレット(Mac では
cmd+shift+p
、Windows ではctrl+shift+p
)を開き、ESLint: Restart ESLint Server
で検索してください。
Next Steps
更新が完了した後は、 next ステップについては以下のセクションをご覧ください:
- 新機能のアップグレード: 改善された Image や Link コンポーネントなど、新機能へのアップグレードをサポートするガイドです。
pages
ディレクトリからapp
ディレクトリへの移行:pages
からapp
ディレクトリへ段階的に移行するためのステップバイステップガイド。
Upgrading New Features
Next.js 13 は、新機能と規約を備えた新しいApp Routerを導入しました。新しい Router は app
ディレクトリで利用可能で、pages
ディレクトリと共存します。
Next.js 13 にアップグレードしても、新しいApp Routerを require で使用する必要はありません。新しい機能を使った pages
の使用を続けることができます。それらの新機能は、アップデートされたImage component、Link component、Script component、そしてFont optimizationなど、どちらのディレクトリでも動作します。
<Image/>
Component
Next.js 12 は、一時的な import:next/future/image
とともに、Image Component に新しい改良を導入しました。これらの改良には、Client 側の JavaScript の削減、画像の拡張や style をより簡単に行う方法、より良いアクセシビリティ、およびブラウザのネイティブな lazy loading が含まれています。
version13 では、この新しい動作が next/image
の default になりました。
新しい Image Component に移行するための 2 つの codemods があります:
next-image-to-legacy-image
codemod: 安全かつ自動でnext/image
のインポートをnext/legacy/image
に名前変更します。既存の Component は同じ動作を維持します。next-image-experimental
コードモッド: 危険なインラインの styles を追加し、未使用の props を削除します。これにより、既存のコンポーネントの動作が新しい default に合わせて変更されます。このコードモッドを使用するには、まずnext-image-to-legacy-image
コードモッドを実行する必要があります。
<Link>
Component
<Link>
Componentは、子として<a>
タグを手動で追加する必要がなくなりました。この動作は、version 12.2 で実験的なオプションとして追加され、現在は default となっています。Next.js 13 では、<Link>
は常に<a>
をレンダリングし、props を基礎となるタグに転送することを可能にします。
For example:
import Link from 'next/link'
// Next.js 12: `<a>` has to be nested otherwise it's excluded
<Link href="/about">
<a>About</a>
</Link>
// Next.js 13: `<Link>` always renders `<a>` under the hood
<Link href="/about">
About
</Link>
あなたのリンクを Next.js 13 にアップグレードするには、new-link
codemodを使用できます。
<Script>
Component
next/script
の挙動が、pages
とapp
の両方をサポートするように更新されましたが、スムーズな移行を確保するためにはいくつかの変更が必要となります:
- 以前に
_document.js
に含めていた全てのbeforeInteractive
の scripts を、root layout ファイル(app/layout.tsx
)に移動してください。 - 実験的な
worker
strategy はまだapp
で動作せず、この strategy を指定した scripts は削除するか、別の strategy (例:lazyOnload
)を使用するように変更する必要があります。 onLoad
、onReady
、そしてonError
ハンドラーラーは Server Components で動作しませんので、それらをClient Componentに移動するか、完全に削除するように確認してください。
フォント最適化
以前、Next.js はinlining font CSSによってフォントの最適化を支援していました。Version 13 では、新たにnext/font
モジュールが導入され、優れたパフォーマンスとプライバシーを維持しながらフォント loading 経験をカスタマイズする能力を提供します。next/font
は、pages
およびapp
ディレクトリの両方でサポートされています。
pages
でinlining CSSはまだ機能しますが、app
では機能しません。代わりにnext/font
を使用すべきです。
next/font
の使い方を学ぶために、Font Optimizationのページをご覧ください。
Migrating from pages
to app
🎥 視聴: App Router を少しずつ採用する方法を学ぶ → YouTube (16 分) .
App Router への移行は、Next.js が上に構築する React の機能を初めて使用するかもしれません。これには Server Components、Suspense などが含まれます。 特別なファイル や Layout などの新しい Next.js の機能と組み合わされると、移行は新しい概念、思考モデル、行動変更を学習することを意味します。
これらの更新の複合的な複雑さを、移行をより小さなステップに分割することで軽減することをお勧めします。app
ディレクトリは意図的に、ページごとの増分的な移行を可能にするために、pages
ディレクトリと同時に動作するように設計されています。
app
ディレクトリはネストされた routes と Layout をサポートしています。詳しくはこちら。- ネストされたフォルダを使用してroutes を定義すると、特別な
page.js
ファイルを使用して route セグメントを公開することができます。詳しくはこちら。 - Special file conventionsは、それぞれの route セグメントの UI を作成するために使用されます。最も一般的な特別なファイルは、
page.js
とlayout.js
です。page.js
を使用して、route に固有の UI を定義します。layout.js
を使用して、複数の routes で共有される UI を定義してください。- 特別なファイルには、
.js
、.jsx
、または.tsx
のファイル拡張子を使用できます。
- 他のファイルを
app
ディレクトリに共存させることができます。例えば、コンポーネント、 styles 、テストなどです。詳しくはこちら。 getServerSideProps
やgetStaticProps
のようなデータ取得機能は、app
内の新しい APIリンクに置き換えられました。getStaticPaths
はgenerateStaticParams
に置き換えられました。pages/_app.js
とpages/_document.js
は一つのapp/layout.js
root layout に置き換えられました。もっと詳しく。pages/_error.js
は、より詳細なerror.js
特別ファイルに置き換えられました。詳細を学ぶ。pages/404.js
はnot-found.js
ファイルに置き換えられました。pages/api/*
API Routes が特別なファイルroute.js
(Route Handler)に置き換えられました。
ステップ 1: app
ディレクトリの作成
最新の Next.js version に更新してください(13.4 以上が必要):
npm install next@latest
次に、プロジェクトの root(またはsrc/
ディレクトリ)に新しいapp
ディレクトリを作成してください。
ステップ 2:Root Layout の作成
新しい app/layout.tsx
ファイルを app
ディレクトリの中に作成してください。これは、app
内のすべての routes に適用されるroot layoutです。
export default function RootLayout({
// Layouts must accept a children prop.
// This will be populated with nested layouts or pages
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
export default function RootLayout({
// Layouts must accept a children prop.
// This will be populated with nested layouts or pages
children,
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
app
ディレクトリには、root layout が必ず含まれていなければなりません。- root layout は、
<html>
と<body>
タグを定義する必要があります。なぜなら、Next.js はそれらを自動的に作成しないからです。 - root layout は、
pages/_app.tsx
とpages/_document.tsx
ファイルを置き換えます。 - layout ファイルには、
.js
、.jsx
、または.tsx
の拡張子を使用できます。
<head>
HTML 要素を管理するには、組み込みの SEO サポートを使用できます:
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Home',
description: 'Welcome to Next.js',
}
export const metadata = {
title: 'Home',
description: 'Welcome to Next.js',
}
_document.js
と_app.js
の移行
既存の _app
または _document
ファイルがある場合は、内容(例えば、グローバルな Styles )を root layout (app/layout.tsx
) にコピーすることができます。 app/layout.tsx
の styles は、 pages/*
には適用されません。移行中は _app
/_document
を保持し、pages/*
の routes が壊れるのを防ぐべきです。完全に移行が完了したら、それらを安全に delete することができます。
あなたが React Context プロバイダーを使用している場合、それらは Client Componentに移動する必要があります。
getLayout()
パターンの Layouts への移行(オプショナル)
Next.js は、pages
ディレクトリでページごとの Layout を実現するために、PageComponent にプロパティを追加することを推奨しました。このパターンは、app
ディレクトリでのnested layoutsのネイティブサポートに置き換えることができます。
before/after の例を見る
Before
export default function DashboardLayout({ children }) {
return (
<div>
<h2>My Dashboard</h2>
{children}
</div>
)
}
import DashboardLayout from '../components/DashboardLayout'
export default function Page() {
return <p>My Page</p>
}
Page.getLayout = function getLayout(page) {
return <DashboardLayout>{page}</DashboardLayout>
}
After
-
Page.getLayout
プロパティをpages/dashboard/index.js
から削除し、ページのマイグレーション手順に従ってapp
ディレクトリに移行してください。export default function Page() { return <p>My Page</p>; }
-
DashboardLayout
の内容を新しいClient Componentに移動して、pages
ディレクトリの動作を維持してください。"use client"; // this directive should be at top of the file, before any imports. // This is a Client Component export default function DashboardLayout({ children }) { return ( <div> <h2>My Dashboard</h2> {children} </div> ); }
-
app
ディレクトリ内の新しいlayout.js
ファイルにDashboardLayout
を Import してください。import DashboardLayout from "./DashboardLayout"; // This is a Server Component export default function Layout({ children }) { return <DashboardLayout>{children}</DashboardLayout>; }
-
DashboardLayout.js
の非インタラクティブな部分を( Client Component )からlayout.js
( Server Component )に逐次移動させることで、 client に送信する component JavaScript の量を減らすことができます。
ステップ 3: next/head
の移行
pages
ディレクトリでは、next/head
React component が<head>
HTML 要素(title
、meta
など)を管理するために使用されています。app
ディレクトリでは、next/head
は新しい組み込みの SEO サポートに置き換えられます。
Before:
import Head from 'next/head'
export default function Page() {
return (
<>
<Head>
<title>My page title</title>
</Head>
</>
)
}
import Head from 'next/head'
export default function Page() {
return (
<>
<Head>
<title>My page title</title>
</Head>
</>
)
}
After:
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'My Page Title',
}
export default function Page() {
return '...'
}
export const metadata = {
title: 'My Page Title',
}
export default function Page() {
return '...'
}
すべての metadata options を参照してください。
ステップ 4:ページの移行
app
ディレクトリ内のページは、 default でServer Componentsです。これはpages
ディレクトリとは異なり、こちらのページはClient Componentsです。- データ取得は
app
で変更されました。getServerSideProps
、getStaticProps
、およびgetInitialProps
は、よりシンプルな API に置き換えられました。 app
ディレクトリはネストされたフォルダを使用してroutes を定義するため、そして特別なpage.js
ファイルを使用して route セグメントを公にアクセス可能にするためです。
pages ディレクトリ | app ディレクトリ | Route |
---|---|---|
index.js | page.js | / |
about.js | about/page.js | /about |
blog/[slug].js | blog/[slug]/page.js | /blog/post-1 |
ページの移行を主に 2 つのステップに分解することをお勧めします:
- ステップ 1:export された default ページ Component を新しい Client Component に移動します。
- ステップ 2:新しい
app
ディレクトリ内の新しいpage.js
ファイルに新しい Client Component を Import します。
Good to know: これが最も
pages
ディレクトリに近い動作をするため、最も簡単な移行 path です。
ステップ 1:新しい Client Component を作成する
app
ディレクトリ内に新しい別のファイル(例app/home-page.tsx
など)を作成し、その中に Client Component を export します。 Client Components を定義するには、ファイルの先頭(どのインポートよりも前)に'use client'
ディレクティブを追加します。- Pages Router と同様に、初回のページロード時に Client Components を静的 HTML にプレレンダリングするための最適化ステップがあります。
pages/index.js
からapp/home-page.tsx
へと、default という export されたページ component を移動させてください。
'use client'
// This is a Client Component (same as components in the `pages` directory)
// It receives data as props, has access to state and effects, and is
// prerendered on the server during the initial page load.
export default function HomePage({ recentPosts }) {
return (
<div>
{recentPosts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
)
}
'use client'
// This is a Client Component. It receives data as props and
// has access to state and effects just like Page components
// in the `pages` directory.
export default function HomePage({ recentPosts }) {
return (
<div>
{recentPosts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
)
}
ステップ 2:新しいページを作成する
-
新しい
app/page.tsx
ファイルをapp
ディレクトリ内に作成します。これは、 default で Server Component です。 -
ページに
home-page.tsx
の Import Client Component をインポートします。 -
pages/index.js
でデータを取得していた場合、新しいdata fetching APIsを使用してデータ取得のロジックを直接 Server Component に移動します。詳細はdata fetching upgrade guideを参照してください。// Import your Client Component import HomePage from "./home-page"; async function getPosts() { const res = await fetch("https://..."); const posts = await res.json(); return posts; } export default async function Page() { // Fetch data directly in a Server Component const recentPosts = await getPosts(); // Forward fetched data to your Client Component return <HomePage recentPosts={recentPosts} />; }
// Import your Client Component import HomePage from "./home-page"; async function getPosts() { const res = await fetch("https://..."); const posts = await res.json(); return posts; } export default async function Page() { // Fetch data directly in a Server Component const recentPosts = await getPosts(); // Forward fetched data to your Client Component return <HomePage recentPosts={recentPosts} />; }
-
あなたの前のページが
useRouter
を使用していた場合、新しいルーティング hook への更新が必要です。 もっと詳しく。 -
Start を押して、あなたの development server を始め、
EXL0005
にアクセスしてください。すでに存在する index route が、今は app ディレクトリを通じて提供されているはずです。
ステップ 5:ルーティング hook の移行
新しい router が追加され、app
ディレクトリに新しい動作をサポートします。
app
では、next/navigation
からインポートされた 3 つの新しい hook を使用する必要があります:useRouter()
、usePathname()
、そしてuseSearchParams()
。
- 新しい
useRouter
hook は、next/navigation
からインポートされ、next/router
からインポートされるpages
の中のuseRouter
hook とは異なる動作を持っています。next/router
からインポートされるuseRouter
hookは、app
ディレクトリではサポートされていませんが、pages
ディレクトリでは引き続き使用できます。
- 新しい
useRouter
はpathname
の string を返しません。代わりに別のusePathname
の hook を使用してください。 - 新しい
useRouter
はquery
の object を返しません。代わりに、別のuseSearchParams
の hook を使用してください。 useSearchParams
とusePathname
を同時に使用してページの変更をリスンすることができます。詳細はRouter Eventsセクションを参照してください。- これらの新しい hook は、Client Components でのみサポートされています。Server Components では使用できません。
'use client'
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
export default function ExampleClientComponent() {
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
// ...
}
'use client'
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
export default function ExampleClientComponent() {
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
// ...
}
さらに、新たな useRouter
hook には以下の変更があります:
isFallback
は削除されました。なぜなら、fallback
が置き換えられましたからです。locale
、locales
、defaultLocales
、domainLocales
の値は、app
ディレクトリでビルトインの i18n Next.js 機能がもはや必要ないため削除されました。i18n についてもっと学ぶ。basePath
は削除されました。代替手段はuseRouter
の一部にはなりません。まだ実装されていません。asPath
は削除されました。なぜなら、新しい router からas
の概念が削除されたからです。isReady
はもはや必要ないため、削除されました。 static renderingの間に、useSearchParams()
hook を使用するあらゆる component は、プレレンダリングステップをスキップし、代わりに client で runtime にレンダリングされます。
useRouter()
API reference を見る。
ステップ 6:データ取得方法の移行
pages
ディレクトリは、ページのデータを fetch するために getServerSideProps
と getStaticProps
を使用します。app
ディレクトリ内では、これらの以前のデータフェッチ関数は、fetch()
と async
React Server Components を基盤にしたよりシンプルな APIに置き換えられます。
export default async function Page() {
// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache` is the default and can be omitted.
const staticData = await fetch(`https://...`, { cache: 'force-cache' })
// This request should be refetched on every request.
// Similar to `getServerSideProps`.
const dynamicData = await fetch(`https://...`, { cache: 'no-store' })
// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps` with the `revalidate` option.
const revalidatedData = await fetch(`https://...`, {
next: { revalidate: 10 },
})
return <div>...</div>
}
export default async function Page() {
// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache` is the default and can be omitted.
const staticData = await fetch(`https://...`, { cache: 'force-cache' })
// This request should be refetched on every request.
// Similar to `getServerSideProps`.
const dynamicData = await fetch(`https://...`, { cache: 'no-store' })
// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps` with the `revalidate` option.
const revalidatedData = await fetch(`https://...`, {
next: { revalidate: 10 },
})
return <div>...</div>
}
Server-side Rendering (getServerSideProps
)
pages
ディレクトリでは、getServerSideProps
が使われて server 上のデータを fetch し、props をファイル内の default で export された React component に転送します。このページの初期 HTML は server からプレレンダリングされ、次にブラウザでページを "hydrating"(インタラクティブにする)します。
// `pages` directory
export async function getServerSideProps() {
const res = await fetch(`https://...`)
const projects = await res.json()
return { props: { projects } }
}
export default function Dashboard({ projects }) {
return (
<ul>
{projects.map((project) => (
<li key={project.id}>{project.name}</li>
))}
</ul>
)
}
app
ディレクトリでは、Server Componentsを使用して、ReactComponent 内でデータの取得を共有できます。これにより、server からのレンダリングされた HTML を維持しながら、client へ送る JavaScript の量を減らすことができます。
cache
オプションをno-store
に設定することで、フェッチしたデータがnever キャッシュされるべきではないことを示すことができます。これは、pages
ディレクトリのgetServerSideProps
に似ています。
// `app` directory
// This function can be named anything
async function getProjects() {
const res = await fetch(`https://...`, { cache: 'no-store' })
const projects = await res.json()
return projects
}
export default async function Dashboard() {
const projects = await getProjects()
return (
<ul>
{projects.map((project) => (
<li key={project.id}>{project.name}</li>
))}
</ul>
)
}
// `app` directory
// This function can be named anything
async function getProjects() {
const res = await fetch(`https://...`, { cache: 'no-store' })
const projects = await res.json()
return projects
}
export default async function Dashboard() {
const projects = await getProjects()
return (
<ul>
{projects.map((project) => (
<li key={project.id}>{project.name}</li>
))}
</ul>
)
}
Request Object へのアクセス
pages
ディレクトリでは、Node.js HTTP API に基づいて Request ベースのデータを取得できます。
たとえば、getServerSideProps
からreq
object を取得し、リクエストの cookies や headers を取得するために使用することができます。
// `pages` directory
export async function getServerSideProps({ req, query }) {
const authHeader = req.getHeaders()['authorization'];
const theme = req.cookies['theme'];
return { props: { ... }}
}
export default function Page(props) {
return ...
}
app
ディレクトリは、request データを取得するための新しい読み取り専用の機能を公開します。
headers()
: Web の Headers API に基づいており、Server Components内で request headers を取得するために使用できます。cookies()
: Web の Cookies API に基づき、Server Components内で cookies を取得するために使用できます。
// `app` directory
import { cookies, headers } from 'next/headers'
async function getData() {
const authHeader = headers().get('authorization')
return '...'
}
export default async function Page() {
// You can use `cookies()` or `headers()` inside Server Components
// directly or in your data fetching function
const theme = cookies().get('theme')
const data = await getData()
return '...'
}
// `app` directory
import { cookies, headers } from 'next/headers'
async function getData() {
const authHeader = headers().get('authorization')
return '...'
}
export default async function Page() {
// You can use `cookies()` or `headers()` inside Server Components
// directly or in your data fetching function
const theme = cookies().get('theme')
const data = await getData()
return '...'
}
Static Site Generation(getStaticProps
)
pages
ディレクトリでは、getStaticProps
関数が使用されて、build の時にページを事前にレンダリングします。この関数を使用すると、外部の API からまたは直接データベースからデータを fetch して、そのデータをページ全体に渡すことができます。これは、build の過程で生成されています。
// `pages` directory
export async function getStaticProps() {
const res = await fetch(`https://...`)
const projects = await res.json()
return { props: { projects } }
}
export default function Index({ projects }) {
return projects.map((project) => <div>{project.name}</div>)
}
app
ディレクトリでは、fetch()
によるデータフェッチングは default で cache: 'force-cache'
に設定され、request データが手動で無効にされるまで cache されます。これは pages
ディレクトリの getStaticProps
と似ています。
// `app` directory
// This function can be named anything
async function getProjects() {
const res = await fetch(`https://...`)
const projects = await res.json()
return projects
}
export default async function Index() {
const projects = await getProjects()
return projects.map((project) => <div>{project.name}</div>)
}
Dynamic paths (getStaticPaths
)
pages
ディレクトリでは、getStaticPaths
関数を使用して、build 時に事前に描画するべき dynamic paths を定義します。
// `pages` directory
import PostLayout from '@/components/post-layout'
export async function getStaticPaths() {
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
}
}
export async function getStaticProps({ params }) {
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
return { props: { post } }
}
export default function Post({ post }) {
return <PostLayout post={post} />
}
app
ディレクトリでは、getStaticPaths
は generateStaticParams
に置き換えられています。
generateStaticParams
は、getStaticPaths
と同様の動作をしますが、route パラメータを返すための簡略化された API を持ち、layoutsの中で使用できます。generateStaticParams
の返り値の形状は、ネストされたparam
Object の配列や解決された paths の string ではなく、セグメントの配列です。
// `app` directory
import PostLayout from '@/components/post-layout'
export async function generateStaticParams() {
return [{ id: '1' }, { id: '2' }]
}
async function getPost(params) {
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
return post
}
export default async function Post({ params }) {
const post = await getPost(params)
return <PostLayout post={post} />
}
新しいモデルにとって、app
ディレクトリ内で getStaticPaths
よりも generateStaticParams
という名前を使用する方が適切です。get
という接頭辞は、もっと説明的な generate
に置き換えられ、getStaticProps
と getServerSideProps
が必要なくなったため、今では単独での使用が適切です。また、 Paths
というサフィックスは、複数の dynamic セグメントを持つネストされたルーティングに適したParams
に置き換えられました。
fallback
の置き換え
pages
ディレクトリでは、getStaticPaths
から返されるfallback
プロパティを使用して、 build 時に事前にレンダリングされていないページの動作を定義します。このプロパティは、ページが生成されている間に fallback ページを表示するためにtrue
に設定するか、404 ページを表示するためにfalse
に設定するか、または request 時にページを生成するためにblocking
に設定することができます。
// `pages` directory
export async function getStaticPaths() {
return {
paths: [],
fallback: 'blocking'
};
}
export async function getStaticProps({ params }) {
...
}
export default function Post({ post }) {
return ...
}
app
ディレクトリでは、config.dynamicParams
プロパティが、generateStaticParams
の外部にある params の処理方法を制御します。
true
: ( default )generateStaticParams
に含まれていない Dynamic セグメントは、要求に応じて生成されます。false
:generateStaticParams
に含まれていない Dynamic セグメントは 404 を返します。
これは pages
ディレクトリの getStaticPaths
の fallback: true | false | 'blocking'
オプションを置き換えます。fallback: 'blocking'
オプションは、'blocking'
と true
との違いがストリーミングでは無視できる程度だから dynamicParams
に含まれていません。
// `app` directory
export const dynamicParams = true;
export async function generateStaticParams() {
return [...]
}
async function getPost(params) {
...
}
export default async function Post({ params }) {
const post = await getPost(params);
return ...
}
dynamicParams
がtrue
に設定されている場合(“ default )、生成されていない route セグメントが要求されたとき、それは servers で rendering され cache されます。
Incremental Static Regeneration (getStaticProps
とrevalidate
を使用して)
pages
ディレクトリでは、getStaticProps
関数を使用してrevalidate
フィールドを追加することで、一定時間後にページを自動的に再生成することができます。
// `pages` directory
export async function getStaticProps() {
const res = await fetch(`https://.../posts`)
const posts = await res.json()
return {
props: { posts },
revalidate: 60,
}
}
export default function Index({ posts }) {
return (
<Layout>
<PostList posts={posts} />
</Layout>
)
}
app
ディレクトリでは、fetch()
を用いたデータフェッチングは revalidate
を使用することができ、これにより指定された秒数にわたって request を cache します。
// `app` directory
async function getPosts() {
const res = await fetch(`https://.../posts`, { next: { revalidate: 60 } })
const data = await res.json()
return data.posts
}
export default async function PostList() {
const posts = await getPosts()
return posts.map((post) => <div>{post.name}</div>)
}
API Routes
pages/api
ディレクトリでは、何も変わらずに API Routes が引き続き作動します。しかし、それらはapp
ディレクトリ内のRoute Handlersに置き換えられました。
Route Handlers allow you to create custom request handlers for a given route using the Web Request and Response APIs.
export async function GET(request: Request) {}
export async function GET(request) {}
Good to know: 以前 APIroutes を使用して client から外部の API を呼び出していた場合、代わりにServer Componentsを使用して安全に fetch データを取得できるようになりました。 data fetchingについて詳しく学ぶ。
ステップ 7:スタイリング
pages
ディレクトリでは、グローバルスタイルシートはpages/_app.js
のみに制限されています。しかし、app
ディレクトリでは、この制限が解除されました。グローバルな styles は、任意の layout 、ページ、または component に追加することができます。
Tailwind CSS
もし Tailwind CSS を使用しているなら、app
ディレクトリをtailwind.config.js
ファイルに追加する必要があります:
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx,mdx}', // <-- Add this line
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
],
}
また、グローバルな styles をあなたの app/layout.js
ファイルに import する必要があります:
import '../styles/globals.css'
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
Tailwind CSS を使ったスタイリングについてもっと詳しく学びましょう。
Codemods
Next.js は、機能が非推奨になったときにコードベースのアップグレードを支援するための Codemod 変換を提供します。詳細はCodemodsを参照してください。