useRouter
あなたが app 内の任意の component 内でrouter
objectにアクセスしたい場合、useRouter
hook を使用することができます。以下の例をご覧ください:
import { useRouter } from "next/router";
function ActiveLink({ children, href }) {
const router = useRouter();
const style = {
marginRight: 10,
color: router.asPath === 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を使用するか、クラスを component の関数内に置くことができます。
router
object
以下は、useRouter
とwithRouter
の両方が返すrouter
object の定義です:
pathname
:String
- 現在の route ファイルの path で、/pages
の後に来ます。したがって、basePath
、locale
および末尾のスラッシュ(trailingSlash: true
)は含まれていません。query
:Object
- クエリー string が object にパースされ、dynamic routeのパラメータを含みます。ページがServer-side Renderingを使用していない場合、プレ rendering 中に空のオブジェクトになります。{}
が default です。asPath
:String
- ブラウザで表示される path で、検索 params を含み、trailingSlash
設定を尊重しています。basePath
とlocale
は含まれていません。isFallback
:boolean
- 現在のページがfallback modeにあるかどうか。basePath
:String
- アクティブなbasePath(有効な場合)。locale
:String
- アクティブな locale (有効な場合)。locales
:String[]
- 有効にした場合、すべてのサポートされている locales 。defaultLocale
:String
- 現在の default locale(有効な場合)。domainLocales
:Array<{domain, defaultLocale, locales}>
- 任意の設定されたドメイン locales。isReady
:boolean
- router のフィールドが Client 側で更新され、使用可能になっているかどうか。useEffect
Method 内でのみ使用すべきであり、server で条件付きレンダリングには使用しないでください。自動的に静的に最適化されたページの使用例に関する関連ドキュメントを参照してください。isPreview
:boolean
- アプリケーションが現在preview モードにあるかどうか。
asPath
フィールドを使用すると、ページが server-side rendering またはautomatic static optimizationを使用してレンダリングされる場合、client と server の間に不一致が生じる可能性があります。isReady
フィールドがtrue
になるまでasPath
の使用を避けてください。
次の Method はrouter
内に含まれています:
router.push
Client 側の遷移を処理し、この method はnext/link
が十分でない場合に役立ちます。
router.push(url, as, options);
url
:UrlObject | String
- ナビゲートする URL (UrlObject
プロパティについてはNode.JS URL モジュールのドキュメンテーション を参照してください)。as
:UrlObject | String
- ブラウザの URL バーに表示される path のオプションのデコレータ。 Next.js 9.5.3 より前では、これは dynamic routes に使用されていました。options
- 以下の設定 options を持つ任意の object :scroll
- オプションの boolean で、ナビゲーション後にページのトップまでスクロールするかどうかを制御します。default はtrue
です。shallow
:現在のページの path を更新しますが、getStaticProps
、getServerSideProps
、またはgetInitialProps
を再実行せずに行います。default はfalse
です。
locale
- 任意の string で、新しいページの locale を示します
外部の URL には
router.push
を使う必要はありません。そのような場合には、window.location の方が適しています。
pages/about.js
に移動します。これは定義済みの route です:
import { useRouter } from "next/router";
export default function Page() {
const router = useRouter();
return (
<button type="button" onClick={() => router.push("/about")}>
Click me
</button>
);
}
pages/post/[pid].js
を操作する、これは dynamic route です:
import { useRouter } from "next/router";
export default function Page() {
const router = useRouter();
return (
<button type="button" onClick={() => router.push("/post/abc")}>
Click me
</button>
);
}
ユーザーを pages/login.js
に Redirect する、認証の背後にあるページに便利:
import { useEffect } from "react";
import { useRouter } from "next/router";
// Here you would fetch and return the user
const useUser = () => ({ user: null, loading: false });
export default function Page() {
const { user, loading } = useUser();
const router = useRouter();
useEffect(() => {
if (!(user || loading)) {
router.push("/login");
}
}, [user, loading]);
return <p>Redirecting...</p>;
}
ナビゲーション後の状態のリセット
Next.js で同じページに移動するとき、ページの状態は default ではリセットされません。なぜなら React は親の component が変更されない限りアンマウントされないからです。
import Link from 'next/link'
import { useState } from 'react'
import { useRouter } from 'next/router'
export default function Page(props) {
const router = useRouter()
const [count, setCount] = useState(0)
return (
<div>
<h1>Page: {router.query.slug}</h1>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase count</button>
<Link href="/one">one</Link> <Link href="/two">two</Link>
</div>
)
}
上記の例では、/one
と/two
の間を移動してもカウントはリセットされません。上位レベルの React component であるPage
が同じであるため、useState
はレンダリング間で維持されます。
この動作を望まない場合、いくつかの options があります:
-
useEffect
を使用して各状態が更新されるよう手動で確認します。上記の例では、以下のようになる可能性があります。useEffect(() => { setCount(0); }, [router.query.slug]);
-
React の
key
を使ってReact に component を再マウントさせること を伝えます。すべてのページでこれを行うために、カスタムの app を使用することができます。import { useRouter } from "next/router"; export default function MyApp({ Component, pageProps }) { const router = useRouter(); return <Component key={router.asPath} {...pageProps} />; }
URL object と共に
next/link
を使用するのと同じ方法で URL object を使用することができます。これは、url
とas
の両方のパラメータに対して機能します。
import { useRouter } from "next/router";
export default function ReadMore({ post }) {
const router = useRouter();
return (
<button
type="button"
onClick={() => {
router.push({
pathname: "/post/[pid]",
query: { pid: post.id },
});
}}
>
Click here to read more
</button>
);
}
router.replace
replace
prop と同様にnext/link
で、router.replace
は新しい URL エントリをhistory
stack に追加することを防ぎます。
router.replace(url, as, options);
router.replace
のための API は、router.push
の API とまったく同じです。
以下の例を見てください:
import { useRouter } from "next/router";
export default function Page() {
const router = useRouter();
return (
<button type="button" onClick={() => router.replace("/home")}>
Click me
</button>
);
}
router.prefetch
Client サイドの遷移を速くするために、Prefetch ページ。この method は、next/link
がないナビゲーションにのみ役立ちます。なぜなら、next/link
は自動的にページをプリフェッチします。
これは production 専用の機能です。Next.js は development 中に prefetch ページを行いません。
router.prefetch(url, as, options);
url
- URL は prefetch するためのもので、明示的な routes (例:/dashboard
)や dynamic routes (例:/product/[id]
)を含みます。as
-url
用のオプションのデコレーターです。Next.js 9.5.3 より前には、これが prefetch dynamic routes に使用されていました。options
- 以下の許可されたフィールドを持つオプションの object:locale
- アクティブな locale とは異なる locale を提供することができます。false
の場合は、locale がアクティブな locale として使用されないため、url
に locale を含める必要があります。
あなたがログインページを持っていて、ログイン後、ユーザーを dashboard に redirect します。その場合、次の例のように、より速い遷移を実現するために、dashboard を prefetch できます。
import { useCallback, useEffect } from "react";
import { useRouter } from "next/router";
export default function Login() {
const router = useRouter();
const handleSubmit = useCallback((e) => {
e.preventDefault();
fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
/* Form data */
}),
}).then((res) => {
// Do a fast client-side transition to the already prefetched dashboard page
if (res.ok) router.push("/dashboard");
});
}, []);
useEffect(() => {
// Prefetch the dashboard page
router.prefetch("/dashboard");
}, [router]);
return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
<button type="submit">Login</button>
</form>
);
}
router.beforePopState
一部のケース(たとえば、Custom Serverを使用する場合など)では、popstate を聞き、router がそれに対して行動する前に何かを行いたいかもしれません。
router.beforePopState(cb);
cb
- 入ってくるpopstate
イベントで実行する関数。この関数は、次の props を含む object としてイベントの状態を受け取ります:url
:String
- 新しい状態のための route。これは通常、page
の名前です。as
:String
- ブラウザに表示される url
options
:Object
- router.pushによって送信される追加の options
cb
がfalse
を返す場合、Next.js router はpopstate
を処理せず、その場合はあなたがそれを処理する責任があります。ファイルシステムルーティングの無効化を参照してください。
beforePopState
を使用して request を操作したり、以下の例のように SSR refresh を強制することができます:
import { useEffect } from "react";
import { useRouter } from "next/router";
export default function Page() {
const router = useRouter();
useEffect(() => {
router.beforePopState(({ url, as, options }) => {
// I only want to allow these two routes!
if (as !== "/" && as !== "/other") {
// Have SSR render bad routes as a 404.
window.location.href = as;
return false;
}
return true;
});
}, [router]);
return <p>Welcome to the page</p>;
}
router.back
履歴に戻ります。これはブラウザの戻るボタンをクリックするのと同等です。window.history.back()
を実行します。
import { useRouter } from "next/router";
export default function Page() {
const router = useRouter();
return (
<button type="button" onClick={() => router.back()}>
Click here to go back
</button>
);
}
router.reload
現在の URL を再読み込みします。これはブラウザの refresh ボタンをクリックするのと同等です。window.location.reload()
を実行します。
import { useRouter } from "next/router";
export default function Page() {
const router = useRouter();
return (
<button type="button" onClick={() => router.reload()}>
Click here to reload
</button>
);
}
router.events
あなたは、Next.js Router 内部で起こる異なるイベントを聞くことができます。以下はサポートされているイベントの一覧です:
routeChangeStart(url, { shallow })
- route が変更を開始するときに発火しますrouteChangeComplete(url, { shallow })
- route が完全に変更されたときに発火しますrouteChangeError(err, url, { shallow })
- routes の変更中に error が発生した場合、または route の読み込みがキャンセルされた場合に発火します。err.cancelled
- ナビゲーションがキャンセルされたかどうかを示します
beforeHistoryChange(url, { shallow })
- ブラウザの履歴を変更する前に発火しますhashChangeStart(url, { shallow })
- ハッシュが変更されるがページは変更されない時に発火しますhashChangeComplete(url, { shallow })
- ハッシュが変更されたがページは変更されていないときに発火します
Good to know: ここで
url
はブラウザに表示される URL を含み、basePath
も含みます。
たとえば、router イベントのrouteChangeStart
を聞くには、pages/_app.js
を開いたり作成したりして、以下のようにイベントを購読します。
import { useEffect } from "react";
import { useRouter } from "next/router";
export default function MyApp({ Component, pageProps }) {
const router = useRouter();
useEffect(() => {
const handleRouteChange = (url, { shallow }) => {
console.log(
`App is changing to ${url} ${
shallow ? "with" : "without"
} shallow routing`
);
};
router.events.on("routeChangeStart", handleRouteChange);
// If the component is unmounted, unsubscribe
// from the event with the `off` method:
return () => {
router.events.off("routeChangeStart", handleRouteChange);
};
}, [router]);
return <Component {...pageProps} />;
}
この例では、ページのナビゲーションでアンマウントされないため、Custom App (
pages/_app.js
)を使用してイベントを購読しますが、アプリケーション内の任意の component で router イベントを購読することも可能です。
Router イベントは component がマウントされる時(useEffect または componentDidMount / componentWillUnmount )や、イベントが発生した時に命令的に登録するべきです。
もし route のロードがキャンセルされる(例えば、短時間で二つのリンクを連続でクリックするなど)場合、routeChangeError
が発火します。そして渡されるerr
には、次の例のようにcancelled
プロパティがtrue
に設定されます:
import { useEffect } from "react";
import { useRouter } from "next/router";
export default function MyApp({ Component, pageProps }) {
const router = useRouter();
useEffect(() => {
const handleRouteChangeError = (err, url) => {
if (err.cancelled) {
console.log(`Route to ${url} was cancelled!`);
}
};
router.events.on("routeChangeError", handleRouteChangeError);
// If the component is unmounted, unsubscribe
// from the event with the `off` method:
return () => {
router.events.off("routeChangeError", handleRouteChangeError);
};
}, [router]);
return <Component {...pageProps} />;
}
Potential ESLint errors
router
object で利用できる特定の方法は Promise を返します。もし ESLint ルール、no-floating-promises が有効になっている場合は、それを全体的に無効にするか、影響を受ける行に対して無効にすることを検討してください。
あなたのアプリケーションがこのルールを必要とする場合、void
で Promise を無効にするか、async
関数を使用して、Promise をawait
し、その後関数の呼び出しを無効にします。これは、method がonClick
の handler 内から呼び出される場合には適用されません。
影響を受ける方法は次の通りです:
router.push
router.replace
router.prefetch
可能な解決策
import { useEffect } from "react";
import { useRouter } from "next/router";
// Here you would fetch and return the user
const useUser = () => ({ user: null, loading: false });
export default function Page() {
const { user, loading } = useUser();
const router = useRouter();
useEffect(() => {
// disable the linting on the next line - This is the cleanest solution
// eslint-disable-next-line no-floating-promises
router.push("/login");
// void the Promise returned by router.push
if (!(user || loading)) {
void router.push("/login");
}
// or use an async function, await the Promise, then void the function call
async function handleRouteChange() {
if (!(user || loading)) {
await router.push("/login");
}
}
void handleRouteChange();
}, [user, loading]);
return <p>Redirecting...</p>;
}
withRouter
もし、useRouter
があなたに最適ではない場合、withRouter
も同じrouter
objectを任意の component に追加することができます。
Usage
import { withRouter } from "next/router";
function Page({ router }) {
return <p>{router.pathname}</p>;
}
export default withRouter(Page);
TypeScript
withRouter
でクラスコンポーネントを使用するには、 component が router プロップを受け入れる必要があります:
import React from "react";
import { withRouter, NextRouter } from "next/router";
interface WithRouterProps {
router: NextRouter;
}
interface MyComponentProps extends WithRouterProps {}
class MyComponent extends React.Component<MyComponentProps> {
render() {
return <p>{this.props.router.pathname}</p>;
}
}
export default withRouter(MyComponent);