Linking and Navigating
Next.js 内での routes 間を移動するための 4 つの方法があります:
<Link>
Component を使用するuseRouter
hook を使用する (Client Components)redirect
関数 (Server Components)を使用する- ネイティブのHistory APIを使用する
このページでは、これらの options の使用方法を紹介し、ナビゲーションの動作についてより深く掘り下げます。
<Link>
Component
<Link>
は、プリフェッチと client サイドのナビゲーションを提供するため、HTML の<a>
タグを拡張する組み込みの component です。これは、Next.js 内の routes 間を移動するための主要で推奨される方法です。
それを next/link
からインポートして使用し、href
プロップを component に渡すことができます。
import Link from 'next/link'
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}
import Link from 'next/link'
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}
他にも <Link>
に渡すことができるオプショナルの props があります。詳しくは API reference をご覧ください。
Examples
Dynamic セグメントへのリンク
dynamic segments にリンクする際、template literals and interpolation を使用してリンクのリストを生成することができます。たとえば、ブログ投稿のリストを生成するには:
import Link from 'next/link'
export default function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}
アクティブリンクの確認
usePathname()
を使用して、link がアクティブかどうかを判断できます。たとえば、アクティブな link にクラスを追加するには、現在の pathname
が link の href
と一致するかどうかを確認できます。
'use client'
import { usePathname } from 'next/navigation'
import Link from 'next/link'
export function Links() {
const pathname = usePathname()
return (
<nav>
<ul>
<li>
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Home
</Link>
</li>
<li>
<Link
className={`link ${pathname === '/about' ? 'active' : ''}`}
href="/about"
>
About
</Link>
</li>
</ul>
</nav>
)
}
'use client'
import { usePathname } from 'next/navigation'
import Link from 'next/link'
export function Links() {
const pathname = usePathname()
return (
<nav>
<ul>
<li>
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Home
</Link>
</li>
<li>
<Link
className={`link ${pathname === '/about' ? 'active' : ''}`}
href="/about"
>
About
</Link>
</li>
</ul>
</nav>
)
}
id
まで Scroll する
Next.js App Router の default の振る舞いは、新しい route のトップへ scroll するか、または前進と戻るナビゲーションの scroll 位置を維持します。
特定の id
まで scroll したい場合、#
ハッシュの link を URL に追加することができます。または、ハッシュの link を href
プロパティに渡すだけでも可能です。これは、<Link>
が <a>
要素にレンダリングされるからです。
<Link href="/dashboard#settings">Settings</Link>
// Output
<a href="/dashboard#settings">Settings</a>
scroll 復元の無効化
default の Next.js App Router の振る舞いは、新しい route の一番上へ scroll するか、後方や前方のナビゲーションで scroll 位置を維持します。この振る舞いを無効にしたい場合は、scroll={false}
を <Link>
component に、または scroll: false
を router.push()
または router.replace()
へ渡すことができます。
// next/link
<Link href="/dashboard" scroll={false}>
Dashboard
</Link>
// useRouter
import { useRouter } from "next/navigation";
const router = useRouter();
router.push("/dashboard", { scroll: false });
useRouter()
hook
useRouter
hook を使用すると、Client Components からプログラムで routes を変更することができます。
'use client'
import { useRouter } from 'next/navigation'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}
useRouter
Method の完全なリストについては、API reference をご覧ください。
おすすめ:
useRouter
を使用する特別な要件がある場合を除き、routes 間を移動するために<Link>
component を使用してください。
redirect
function
Server Components については、代わりに redirect
関数を使用してください。
import { redirect } from 'next/navigation'
async function fetchTeam(id: string) {
const res = await fetch('https://...')
if (!res.ok) return undefined
return res.json()
}
export default async function Profile({ params }: { params: { id: string } }) {
const team = await fetchTeam(params.id)
if (!team) {
redirect('/login')
}
// ...
}
import { redirect } from 'next/navigation'
async function fetchTeam(id) {
const res = await fetch('https://...')
if (!res.ok) return undefined
return res.json()
}
export default async function Profile({ params }) {
const team = await fetchTeam(params.id)
if (!team) {
redirect('/login')
}
// ...
}
Good to know:
redirect
は default では 307(一時的な Redirect)ステータスコードを返します。Server Action で使用すると、303(See Other)を返し、これは POST request の結果として成功ページに Redirect するために一般的に使用されます。redirect
は内部で error をスローするので、try/catch
ブロックの外で呼び出すべきです。redirect
はレンダリングのプロセス中に Client Components で呼び出すことができますが、イベントハンドラーでは呼び出せません。代わりに、useRouter
hook を使用できます。redirect
は絶対 URL も受け入れ、外部リンクに redirect するために使用することができます。- もし render の過程の前に redirect したい場合は、
next.config.js
または Middleware を使用してください。
詳細については、redirect
API referenceをご覧ください。
Using the native History API
Next.js は、ページをリロードせずにブラウザの履歴 stack を更新するためのネイティブな window.history.pushState
と window.history.replaceState
Method を使用することを許可します。
pushState
およびreplaceState
の呼び出しは、Next.js Router と統合され、usePathname
と useSearchParams
との同期を可能にします。
window.history.pushState
それを使用して、ブラウザの履歴 stack に新しいエントリを追加します。ユーザーは以前の状態に戻ることができます。例えば、製品のリストを並べ替えるために:
"use client";
import { useSearchParams } from "next/navigation";
export default function SortProducts() {
const searchParams = useSearchParams();
function updateSorting(sortOrder: string) {
const params = new URLSearchParams(searchParams.toString());
params.set("sort", sortOrder);
window.history.pushState(null, "", `?${params.toString()}`);
}
return (
<>
<button onClick={() => updateSorting("asc")}>Sort Ascending</button>
<button onClick={() => updateSorting("desc")}>Sort Descending</button>
</>
);
}
"use client";
import { useSearchParams } from "next/navigation";
export default function SortProducts() {
const searchParams = useSearchParams();
function updateSorting(sortOrder) {
const params = new URLSearchParams(searchParams.toString());
params.set("sort", sortOrder);
window.history.pushState(null, "", `?${params.toString()}`);
}
return (
<>
<button onClick={() => updateSorting("asc")}>Sort Ascending</button>
<button onClick={() => updateSorting("desc")}>Sort Descending</button>
</>
);
}
window.history.replaceState
それを使用してブラウザの履歴の stack 上の現在のエントリーを replace します。ユーザーは前の状態に戻ることができません。例えば、アプリケーションの locale を切り替えるには:
"use client";
import { usePathname } from "next/navigation";
export function LocaleSwitcher() {
const pathname = usePathname();
function switchLocale(locale: string) {
// e.g. '/en/about' or '/fr/contact'
const newPath = `/${locale}${pathname}`;
window.history.replaceState(null, "", newPath);
}
return (
<>
<button onClick={() => switchLocale("en")}>English</button>
<button onClick={() => switchLocale("fr")}>French</button>
</>
);
}
"use client";
import { usePathname } from "next/navigation";
export function LocaleSwitcher() {
const pathname = usePathname();
function switchLocale(locale) {
// e.g. '/en/about' or '/fr/contact'
const newPath = `/${locale}${pathname}`;
window.history.replaceState(null, "", newPath);
}
return (
<>
<button onClick={() => switchLocale("en")}>English</button>
<button onClick={() => switchLocale("fr")}>French</button>
</>
);
}
How Routing and Navigation Works
App Router は、ルーティングとナビゲーションにハイブリッドアプローチを使用します。 server 上では、アプリケーションのコードが route セグメントで自動的に code -split されます。そして、 client 上では、 Next.js が route セグメントを prefetchesおよび caches します。つまり、ユーザーが新しい route に移動するとき、ブラウザはページを再ロードせず、変更される route のセグメントだけが再 rendering されます - ナビゲーション体験とパフォーマンスが向上します。
1. Code の分割
Code スプリッティングにより、アプリケーションの code を小さなバンドルに分割し、ブラウザでダウンロードして実行できます。これにより、各 request で転送されるデータ量と実行時間が削減され、パフォーマンスが向上します。
Server Components は、アプリケーションの code が route セグメントごとに自動的にコード分割されることを可能にします。これは、現在の route に必要な code のみがナビゲーション時にロードされることを意味します。
2. プリフェッチング
Prefetching は、ユーザーが訪れる前にバックグラウンドで route を preload する方法です。
Next.js では、routes がプリフェッチされる方法は 2 つあります:
<Link>
component: Routes は、ユーザーの viewport に表示されると自動的にプリフェッチされます。プリフェッチは、ページが最初に読み込まれたときや scrolls によって表示されるときに行われます。router.prefetch()
:useRouter
hook は、routes のプリフェッチをプログラムで行うために使用できます。
<Link>
のプリフェッチ動作は静的ルートと dynamic routes では異なります。
- Static Routes:
prefetch
は default でtrue
に設定されています。完全な route が事前に取得されキャッシュされます。 - Dynamic Routes:
prefetch
を default から自動に設定します。共有された layout、レンダリングされた Component の tree の下部から最初のloading.js
ファイルまでが事前に取得され、30s
の間キャッシュされます。これにより、全体的な dynamic route の取得コストが削減され、ユーザーにより視覚的なフィードバックを提供するための、即座に loading 状態を表示することができます。
prefetch
プロップを false
に設定することで、プリフェッチングを無効にすることができます。
詳細は <Link>
API reference をご覧ください。
Good to know:
- プリフェッチングは development では有効になっておらず、production でのみ有効です。
3. キャッシング
Next.js には、Router Cache と呼ばれるメモリ内 Client 側の cacheがあります。ユーザーが app を回覧するとき、prefetched された route セグメントと訪れた routes が cache に保存されます。React Server Component のペイロードも同様です。
これは、ナビゲーションにおいて、新たに request を server に送る代わりに、 cache が可能な限り再利用されることを意味します - number のリクエストとデータ転送量を削減することでパフォーマンスが向上します。
Router Cache の動作と設定方法について詳しく学びましょう。
4. 部分的なレンダリング
部分的なレンダリングとは、ナビゲーションで再レンダリングされる route セグメントのみが client で再レンダリングされ、共有セグメントは保持されるという意味です。
例えば、二つの routes、/dashboard/settings
と/dashboard/analytics
をナビゲートする場合、settings
とanalytics
のページがレンダリングされ、共有のdashboard
layout が保持されます。
部分的なレンダリングがなければ、各ナビゲーションにより全ページが client 上で再レンダリングされます。変更があるセグメントだけをレンダリングすることで、転送されるデータ量と実行時間を減らし、パフォーマンスを向上させることができます。
5. ソフトナビゲーション
ブラウザはページ間を移動する際に "hard navigation" を実行します。 Next.js App Router はページ間の "soft navigation" を可能にし、変更された route セグメントのみが再レンダリング(部分レンダリング)されることを保証します。これにより、ナビゲーション中に client React の状態が維持されます。
6. バックとフォワードナビゲーション
default として、Next.js は、後方および前方のナビゲーションに対して scroll ポジションを保持し、Router Cacheの中で route セグメントを再利用します。
7. pages/
と app/
の間でのルーティング
pages/
からapp/
へと段階的に移行する際には、 Next.js router が自動的に両者の間でのハードなナビゲーションを処理します。pages/
からapp/
への遷移を検出するためには、 app routes の確率的なチェックを活用した client router フィルタがあり、これがたまに false の陽性反応を引き起こすことがあります。 default では、このような事例は非常に稀であるはずです。なぜなら、私たちは false の陽性率を 0.01%に設定しているからです。この確率はnext.config.js
のexperimental.clientRouterFilterAllowedRate
オプションを通じてカスタマイズすることができます。 false の陽性率を下げると、生成されるフィルタの size が client バンドル内で増加することを覚えておくことが重要です。
あるいは、この処理を完全に無効にし、pages/
とapp/
間のルーティングを手動で管理することを選好する場合、next.config.js
でexperimental.clientRouterFilter
を false に設定できます。この機能が無効になると、パージにある任意の dynamic routes が app routes と重複している場合、default では適切に遷移することができません。