アプリ内ページへのリンク(基本)
// import Link from 'next/link'
<Link href="/about">About us</Link>
Next.js でアプリ内部で閉じるページリンクを張るには、next/link モジュールを使用します。
上記のようにすると、pages/about.tsx
ページコンポーネントが生成するページへのリンクになります。
Link
要素の下に明示的に a
要素を配置する必要がありました。
これは、HTML 的に正しく a
要素を配置するためでしたが、Next.js 13 では自動的に a
要素を挿入するようになったので、a
要素の記述は必要ありません。遷移前の履歴を置き換える replace オプション
<Link href="/about" replace>
上記のように replace
オプションを指定すると、ページ遷移前の URL がブラウザの履歴に残りません(戻るキーで戻らなくなります)。
外部リンク
https://
で始まる外部リンクを出力したい場合は、<a>
コンポーネントをそのまま使用します。
next/link
(や react-router
) が提供する Link
コンポーネントは、アプリ内のルーティング用なので使えません。
外部リンクを開く場合は、安全性のために一律で rel="noopener noreferrer"
を付けましょう。
リンククリック時に必ず別タブで開きたいときは、target="_blank"
を指定してください。
<a href="https://example.com/" target="_blank" rel="noopener noreferrer">
Website title
</a>
mui (Material-UI) を採用したサイトの場合は、a
の代わりに mui が提供する Link
コンポーネントを使用することで、サイト内のデザインを統一することができます。
next/link
が提供する Link
コンポーネントと混同しないように、次のように別名 (MuiLink
) を付けて使用すると分かりやすくなります。
// import { Link as MuiLink } from '@mui/material' // mui 版
// import { Link as MuiLink } from '@material-ui/core' // material-ui 版
<MuiLink href="https://example.com/" target="_blank" rel="noopener noreferrer">
Website title
</MuiLink>
外部リンクを出力するときに、毎回上記のような長ったらしいコードを書くのは大変なので、次のような独自コンポーネント (ExternalLink
) などを定義しておくと便利です。
ここでは、ついでに、外部リンクを示す Launch
アイコンを末尾に表示するようにしています。
import { FC } from 'react'
import LaunchIcon from '@mui/icons-material/Launch'
import { Link as MuiLink } from '@mui/material'
// 古い material-ui バージョンの場合
// import LaunchIcon from '@material-ui/icons/Launch'
// import { Link as MuiLink } from '@material-ui/core'
type Props = {
url: string
title: string
}
export const ExternalLink: FC<Props> = ({ url, title }: Props) => {
return (
<MuiLink
href={url} target="_blank" rel="noopener noreferrer"
style={{ display: 'inline-flex', alignItems: 'center' }}
>
{title}
<LaunchIcon fontSize="inherit" />
</MuiLink>
)
}
MuiLink
コンポーネントの style
プロパティは、LaunchIcon
の上下位置をリンク名のテキストに合わせるために設定しています。
<ExternalLink url="https://example.com/" title="サイト名" />

Next.js の Link コンポーネント以下に mui (Material-UI) の UI コンポーネントを配置する
Next.js の Link コンポーネント (next/link
) で独自のコンポーネントをリンクとして動作させるためには、ちょっとしたコツがあります。
mui (Material-UI) は独自のコンポーネントとして、Link や Button を持っており、これらに href
プロパティを指定することによって、a
要素としてレンダリングするようになっています(mui の Link
と Next.js の Link
は別物なので注意)。
ダイレクトに a
要素を使わないのは、mui (Material-UI) が提供する UI 表現を使用するためですね。
// import { Button, Link as MuiLink } from '@mui/material' // mui の場合
// import { Button, Link as MuiLink } from '@material-ui/core' // material-ui の場合
<MuiLink href="/about" underline="none">About us</Link>
<Button href="/about" variant="contained">About us</Button>
これはこれで便利なのですが、Next.js アプリ内での遷移には next/link
を使ったルーティングを行う必要があるため、上記のようには記述できません(クライアントサイド JS でのルーティングが動作しません)。
next/link
モジュールの Link
要素を使って、mui (Material-UI) の UI コンポーネントをリンクとして機能させるには、次のように記述します。
Link
という名前がコンフリクトするため、ここでは、それぞれ NextLink
、MuiLink
という名前でインポートしています(片方だけリネームすれば十分ですが分かりやすくするため両方リネームしています)。
// import NextLink from 'next/link'
// import { Button, Link as MuiLink } from '@mui/material' // mui の場合
// import { Button, Link as MuiLink } from '@material-ui/core' // material-ui の場合
<NextLink href="/about" passHref>
<MuiLink underline="none">About us</MuiLink>
</NextLink>
<NextLink href="/about" passHref>
<Button variant="contained">About us</Button>
</NextLink>
Next.js の Link
コンポーネント (next/link
) の href
プロパティで指定した値を子要素に伝搬させるために、passHref
プロパティを指定するのがポイントです。
passHref
を指定しなくても、Next.js のクライアントサイド JS でリンク機能が動作するため、一見正しく動いているかのように見えますが、a
要素の href
属性がされないため、SEO 的に不利な Web サイトになってしまいます(さらに、mui の Button
コンポーネントの場合は、href
が渡されないと、a
要素ではなく button
要素として出力されてしまいます)。
プログラム内部でリダイレクト (Router.replace, window.location)
// import Router from 'next/router'
Router.replace('/list/users')
Router.replace
を使うと、リダイレクト前の URL がブラウザの履歴に残りません(最初からこの URL でアクセスしたかのように振る舞います)。
アプリ内のルーティングではなく、外部 URL へ移動する場合は、next/router
ではなく window.location
を使用します。
これは、外部リンク用のコンポーネントとして next/link
ではなく <a>
を使用するのと同じ理由です。
クエリパラメーターを変更するリンク
リンクをクリックしたときに、URL 末尾のクエリパラメーター部分(?key=value
みたいなところ)を変更したいときは、Next.js の Link
コンポーネントの href
属性に、URL を表す文字列の代わりに UrlObject
オブジェクトを指定します。
このオブジェクトの query
プロパティで指定した値が、遷移先の URL の末尾にクエリパラメーターとして付加されます。
// import NextLink from 'next/link'
<NextLink href={{
query: {
key1: 'value1',
key2: 'value2',
},
}}>...</NextLink>
上記のようにすると、ページのパス自体は変更されず、クエリパラメーター部分だけが変更されます。
例えば、https://example.com/hello
ページから上記リンクをクリックすると、URL は https://example.com/hello?key1=value1&key2=value2
に変化します。
リンククリック時にパス部分も変更したい場合(ページ遷移したい場合)は、次のように href
プロパティを一緒に指定します。
<NextLink href={{
href: './other-page',
query: {
key1: 'value1',
key2: 'value2',
},
}}>
カレント URL に含まれているクエリパラメーターの一部だけを変更したい場合は、useRouter
フックで現在のクエリパラメーターを取得した上で、変更する値を組み合わせます。
import { RC } from 'react'
import NextLink from 'next/link'
import { useRouter } from 'next/router'
export const MyComponent: FC = () => {
const router = useRouter()
const query = router.query // カレント URL に含まれるクエリパラメーター
return <>
<NextLink
href={{
query: {
...query,
key2: 'newValue',
},
}}
>...</NextLink>
</>
}
上記のリンクをクリックすると、URL のクエリパラメーターの key2=newValue
という部分だけが書き変わります(他のパラメーターは維持されます)。
Link
コンポーネントではなく、関数呼び出しでクエリパラメーターを変更したいときは、router.push
や router.replace
に同様のオブジェクトを渡してやれば OK です。
関連記事
- MUI コンポーネント (v4) に独自のスタイルを設定する (makeStyles)
- Next.js で Material-UI を使う
- Next.js の public 以下のファイルのパスを正しく扱う
- ESLint (4) ESLint の設定方法まとめ (for Next.js 11)
- Next.js アプリのディレクトリ構成を考える(Atomic Design と Presentational and Container Components)
- Next.js でハッシュフラグメントを扱う(useHash カスタムフック)
- Next.js で環境変数を扱う (.env, NEXT_PUBLIC, NODE_ENV)