先に進む前に、まずはルーティング入門をお読みになることをお勧めします。
アプリ内の関数コンポーネントの中で router
オブジェクト へアクセスしたいときは、 useRouter
フックを利用できます。以下の例をご覧ください:
import { useRouter } from 'next/router';
function ActiveLink({ children, href }) {
const router = useRouter();
const style = {
marginRight: 10,
color: router.pathname === href ? 'red' : 'black'
};
const handleClick = e => {
e.preventDefault();
router.push(href);
};
return (
<a href={href} onClick={handleClick} style={style}>
{children}
</a>
);
}
export default ActiveLink;
useRouter
は、React Hook であり、したがってクラスとともに使用することはできません。withRouter を利用するか、関数コンポーネントでクラスをラップしてください。
useRouter
と withRouter
の両方から返却される router
オブジェクトの定義は以下のとおりです:
pathname
: String
- 現在のルートです。 これは /pages
ディレクトリでのページのパスです。query
: Object
- オブジェクトに解釈されたクエリ文字列です。ページにデータ取得要求 が含まれなければ、プリレンダリング時には空オブジェクトになります。デフォルトでは {}
になります。asPath
: String
- ブラウザに表示される実際のパス(クエリも含まれる)です。加えて、Router API
もまたこのオブジェクトに含まれます。
useRouter
が最適でない場合、withRouter
を使うことで同様の router
オブジェクトをコンポーネントに加えることができます。使い方は以下のとおりです:
import { withRouter } from 'next/router';
function Page({ router }) {
return <p>{router.pathname}</p>;
}
export default withRouter(Page);
Router
の API は next/router
からエクスポートされます。Router API は以下のように定義されています。
クライアント側のページ遷移を処理します。このメソッドは next/link
では不十分な場合に役立ちます。
import Router from 'next/router';
Router.push(url, as, options);
url
- 遷移先の URL です。通常、page
の名前です。as
- URL のオプションのデコレータで、ブラウザに表示されます。デフォルトは url
です。options
- 以下の設定オプションを持つ、オプションのオブジェクトです:shallow
: getStaticProps
、getServerSideProps
あるいは getInitialProps
を再実行することなく現在のページのパスを更新します。デフォルトでは false
です。外部 URL に対しては
Router
を使う必要がありません。この場合は window.location がより適しています。
事前に定義されたルートである pages/about.js
へ遷移する場合:
import Router from 'next/router';
function Page() {
return <span onClick={() => Router.push('/about')}>Click me</span>;
}
動的ルートの pages/post/[pid].js
へ遷移する場合:
import Router from 'next/router';
function Page() {
return <span onClick={() => Router.push('/post/[pid]', '/post/abc')}>Click me</span>;
}
URL オブジェクトは、next/link
で URL オブジェクトを用いる場合と同じように扱うことができます。url
と as
パラメータの両方で有効です:
import Router from 'next/router';
const handler = () => {
Router.push({
pathname: '/about',
query: { name: 'Vercel' }
});
};
function ReadMore() {
return (
<div>
Click <span onClick={handler}>here</span> to read more
</div>
);
}
export default ReadMore;
next/link
の replace
prop に似ています。Router.replace
を使うと、history
スタックに新しい URL エントリは追加されません。次の例をご覧ください:
import Router from 'next/router';
Router.replace('/home');
Router.replace
の API は Router.push
で使われる API と全く同じです。
クライアント側のページ遷移を高速化するためにページをプリフェッチします。このメソッドは next/link
を用いないページ遷移においてのみ有用です。というのも、next/link
は自動的にページのプリフェッチ周りの面倒を見てくれるからです。
この API は、本番環境限定の機能です。Next.js は開発環境ではページをプリフェッチしません。
import Router from 'next/router';
Router.prefetch(url, as);
url
- pages
ディレクトリに含まれる page
へのパスです。as
- url
のオプションのデコレータであり、動的ルート をプリフェッチするために用いられます。デフォルトでは url
です。例えば、ログインページがあり、ログイン後にユーザーをダッシュボードへリダイレクトさせるとしましょう。こうしたケースでは、より高速にページ遷移すべくダッシュボードをプリフェッチできます。次の例のようになります:
import { useCallback, useEffect } from 'react';
import Router from 'next/router';
export default function Login() {
const handleSubmit = useCallback(e => {
e.preventDefault();
fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
/* フォームのデータ */
})
}).then(res => {
// プリフェッチ済みのダッシュボードページに、クライアント側で高速に遷移します
if (res.ok) Router.push('/dashboard');
});
}, []);
useEffect(() => {
// ダッシュボードページをプリフェッチします。ユーザーがログイン後にそのページを訪れることになるからです。
Router.prefetch('/dashboard');
}, []);
return (
<form onSubmit={handleSubmit}>
{/* フォームのフィールド */}
<button type="submit">Login</button>
</form>
);
}
場合によっては(例えば、カスタムサーバーを使用する場合)、popstate をリッスンして、ルーターが動作する前に何かしたいということがあります。
これを用いてリクエストを操作したり、SSR によるリフレッシュを強制したりできます。以下に示す例のようになります:
import Router from 'next/router';
Router.beforePopState(({ url, as, options }) => {
// この 2 つのルートだけを許可したい!
if (as !== '/' && as !== '/other') {
// 不正なルートは 404 として SSR でレンダリングする
window.location.href = as;
return false;
}
return true;
});
Router.beforePopState(cb: () => boolean)
cb
- 入力された popstate
イベントに対して実行される関数です。この関数は、以下の props を持つオブジェクトとしてイベントの状態を受け取ります:url
: String
- 新しい state のためのルートです。これは通常 page
の名前です。as
: String
- ブラウザに表示される URL です。options
: Object
- Router.push によって送信される追加のオプションです。beforePopState
に渡した関数が false
を返却する場合、Router
は popstate
を処理しないため、その場合は自分の責任で popstate
を処理することになります。 ファイルシステムのルーティングを無効化する をご覧ください。
履歴を遡ります。ブラウザの戻るボタンをクリックするのと同じです。window.history.back()
が実行されます。
import Router from 'next/router';
Router.back();
現在の URL をリロードします。ブラウザの更新ボタンをクリックするのと同じです。window.location.reload()
が実行されます。
import Router from 'next/router';
Router.reload();
Router 内で発生する様々なイベントをリッスンできます。こちらがサポートされているイベントの一覧です:
routeChangeStart(url)
- ルートの変更が開始した時に発火します。routeChangeComplete(url)
- ルートが完全に変更され終わったときに発火します。routeChangeError(err, url)
- ルート変更時にエラーが発生した際、あるいはルートの読み込みが中止された際に発火します。err.cancelled
- ページ遷移が中止されたかどうかを示します。beforeHistoryChange(url)
-ブラウザの履歴を変更する直前に発火します。hashChangeStart(url)
- ハッシュが変更されるが、ページが変更されないときに発火します。hashChangeComplete(url)
- ハッシュの変更が完了したが、ページが変更されないときに実行されます。ここでの
url
はブラウザに表示されている URL です。Router.push(url, as)
(あるいは類似のメソッド)を呼び出すと、url
の値はas
になります。
例えば、ルーターのイベント routeChangeStart
をリッスンするには次のようにしてください:
import Router from 'next/router';
const handleRouteChange = url => {
console.log('App is changing to: ', url);
};
Router.events.on('routeChangeStart', handleRouteChange);
イベントをリッスンしたくなくなったら、off
メソッドを使って購読を解除してください。
import Router from 'next/router';
Router.events.off('routeChangeStart', handleRouteChange);
ルートの読み込みがキャンセルされたら(例えば、2 つのリンクを続けて素早くクリックした場合)、routeChangeError
が発火します。そして、渡される err
には、以下の例のように、true
がセットされた cancelled
プロパティが含まれます:
import Router from 'next/router';
Router.events.on('routeChangeError', (err, url) => {
if (err.cancelled) {
console.log(`Route to ${url} was cancelled!`);
}
});
ルーターのイベントは、コンポーネントがマウントされたとき(useEffect または componentDidMount / componentWillUnmount)あるいはイベント発生時に、以下の例のように imperatively に登録する必要があります:
import Router from 'next/router';
useEffect(() => {
const handleRouteChange = url => {
console.log('App is changing to: ', url);
};
Router.events.on('routeChangeStart', handleRouteChange);
return () => {
Router.events.off('routeChangeStart', handleRouteChange);
};
}, []);