リンクとナビゲーション
Next.jsのルーターを使用すると、シングルページアプリケーションと同様に、ページ間でクライアントサイドのルート遷移を実現できます。
クライアントサイドのルート遷移を行うために、Link
というReactコンポーネントが提供されています。
import Link from 'next/link'
function Home() {
return (
<ul>
<li>
<Link href="/">ホーム</Link>
</li>
<li>
<Link href="/about">会社概要</Link>
</li>
<li>
<Link href="/blog/hello-world">ブログ投稿</Link>
</li>
</ul>
)
}
export default Home
上記の例では複数のリンクを使用しています。各リンクはパス(href
)を既知のページにマッピングしています:
/
→pages/index.js
/about
→pages/about.js
/blog/hello-world
→pages/blog/[slug].js
ビューポート内(初期表示時またはスクロールにより表示された)のすべての <Link />
は、静的生成(Static Generation)を使用するページに対して、デフォルトで(対応するデータを含めて)プリフェッチされます。サーバーサイドレンダリング(SSR)を使用するルートの対応データは、<Link />
がクリックされた時点でのみフェッチされます。
動的パスへのリンク
動的ルートセグメントに対しては、パスを作成するために補間(interpolation)を使用することもできます。例えば、コンポーネントにプロップとして渡された投稿のリストを表示する場合:
import Link from 'next/link'
function Posts({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${encodeURIComponent(post.slug)}`}>
{post.title}
</Link>
</li>
))}
</ul>
)
}
export default Posts
この例では、パスをUTF-8互換に保つために
encodeURIComponent
を使用しています。
別の方法として、URLオブジェクトを使用することもできます:
import Link from 'next/link'
function Posts({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link
href={{
pathname: '/blog/[slug]',
query: { slug: post.slug },
}}
>
{post.title}
</Link>
</li>
))}
</ul>
)
}
export default Posts
この場合、パスを作成するために補間を使用する代わりに、href
にURLオブジェクトを使用しています:
pathname
はpages
ディレクトリ内のページ名です。この場合は/blog/[slug]
query
は動的セグメントを持つオブジェクトです。この場合はslug
ルーターの注入
例
Reactコンポーネント内で router
オブジェクト にアクセスするには、useRouter
または withRouter
を使用できます。
一般的には useRouter
の使用を推奨します。
命令的なルーティング
例
next/link
でほとんどのルーティングニーズを満たせますが、それを使わずにクライアントサイドナビゲーションを行うこともできます。next/router
のドキュメント を参照してください。
以下の例は、useRouter
を使用した基本的なページナビゲーションの方法を示しています:
import { useRouter } from 'next/router'
export default function ReadMore() {
const router = useRouter()
return (
<button onClick={() => router.push('/about')}>
詳細を読む
</button>
)
}
シャロー(浅い)ルーティング
シャロー・ルーティングを使用すると、データ取得メソッド(getServerSideProps
、getStaticProps
、getInitialProps
)を再実行せずにURLを変更できます。
状態を失うことなく、useRouter
または withRouter
によって追加された router
オブジェクト から、更新された pathname
と query
を受け取ります。
シャロー・ルーティングを有効にするには、shallow
オプションを true
に設定します。次の例を考えてみましょう:
import { useEffect } from 'react'
import { useRouter } from 'next/router'
// 現在のURLは '/'
function Page() {
const router = useRouter()
useEffect(() => {
// 初回レンダリング後に常にナビゲーションを実行
router.push('/?counter=10', undefined, { shallow: true })
}, [])
useEffect(() => {
// カウンターが変更されました!
}, [router.query.counter])
}
export default Page
URLは /?counter=10
に更新されますが、ページは置き換えられず、ルートの状態のみが変更されます。
また、以下のように componentDidUpdate
を使用してURLの変更を監視することもできます:
componentDidUpdate(prevProps) {
const { pathname, query } = this.props.router
// 無限ループを避けるためにプロップが変更されたことを確認
if (query.counter !== prevProps.router.query.counter) {
// 新しいクエリに基づいてデータを取得
}
}
注意点
シャロー・ルーティングは、現在のページ内でのURL変更に対してのみ機能します。例えば、pages/about.js
という別のページがある場合、次のコードを実行すると:
router.push('/?counter=10', '/about?counter=10', { shallow: true })
これは新しいページであるため、現在のページをアンロードし、新しいページをロードし、シャロー・ルーティングを要求したにもかかわらずデータ取得を待機します。
シャロー・ルーティングがミドルウェアと共に使用される場合、以前のように新しいページが現在のページと一致することを保証しません。これは、ミドルウェアが動的に書き換えることが可能で、データ取得なしではクライアントサイドで検証できないためです(シャロー・ルーティングではデータ取得がスキップされます)。したがって、シャロー・ルート変更は常に浅いものとして扱う必要があります。