🚀

【Next.js和訳】API Reference/ next/router

14 min read

この記事について

株式会社 UnReact はプロジェクトの一環としてNext.js ドキュメントの和訳を行っています。

この記事は、next/routerの記事を和訳したものです。

記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。


next/router

先に進む前に、まず「ルーティング入門」をお読みいただくことをお勧めします。

useRouter

アプリ内の任意の関数コンポーネントでrouterオブジェクトにアクセスしたい場合は、useRouter フックを使用できます。

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

useRouterReact Hook なので、クラスと一緒に使うことはできません。withRouter を使用するか、クラスを関数コンポーネントでラップすることができます。

routerオブジェクト

useRouterwithRouterの両方から返されるrouterオブジェクトの定義を以下に示します。

  • pathname: String - 現在のルート。これは、/pagesにあるページのパスで、設定されたbasePathlocaleは含まれません。
  • query: Object - オブジェクトに解析されたクエリ文字列です。ページにデータ取得の要件がない場合、プリレンダリング中は空のオブジェクトになります。デフォルトは {} です。
  • asPath: String - 設定された basePath やロケールを除いた、ブラウザに表示されるパス(クエリを含む)です。
  • isFallback: boolean - 現在のページがフォールバックモードであるかどうかです。
  • basePath: String - アクティブな basePath(有効な場合)です。
  • locale: String - 有効なロケール(有効な場合)
  • locales: String[] - サポートされているすべてのロケールです (有効な場合)。
  • defaultLocale: String - 現在のデフォルトのロケールです (有効な場合)。
  • domainLocales: Array<{domain, defaultLocale, locales}> - 構成されたすべてのドメインロケールです。
  • isReady: boolean - ルーターのフィールドがクライアントサイドで更新され、使用可能かどうかを示します。useEffect メソッドの中でのみ使用されるべきで、サーバー上で条件付きでレンダリングするためではありません。
  • isPreview: boolean - アプリケーションが現在プレビューモードにあるかどうか。
    さらに、以下のメソッドもルータの内部に含まれています。

また、以下の方法もrouter内に含まれています。

router.push

クライアントサイドのトランジションを処理します。このメソッドは、next/linkだけでは不十分な場合に便利です。

router.push(url, as, options)
  • url - 遷移先の URL
  • as - ブラウザに表示される URL のオプションのデコレーターです。Next.js 9.5.3 より前のバージョンでは、このデコレーターはダイナミックルートに使用されていましたが、その仕組みについては以前のドキュメントをご覧ください。
  • options - オプションのオブジェクトで、以下の設定オプションがあります。
    • scroll - オプションのブール値で、ナビゲーション後にページの先頭にスクロールするかどうかを制御します。デフォルトは true です。
    • shallow - getStaticProps, getServerSideProps, getInitialProps を再実行せずに、現在のページのパスを更新します。既定は false です。
  • locale - オプションの文字列,新しいページのロケールを示します

router.push を外部 URL に使用する必要はありません。そのような場合には window.location の方が適しています。

使用方法

定義済みのルートであるpages/about.jsに移動します。

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 をナビゲートしています。

import { useRouter } from "next/router"
export default function Page() {
  const router = useRouter()
  return (
    <button type="button" onClick={() => router.push("/post/abc")}>
      Click me
    </button>
  )
}

注意
Next.js で同じページに移動する場合、トップレベルの React コンポーネントが同じであるため、ページの状態はデフォルトではリセットされません。useEffect を使って手動で状態が更新されるようにすることができます。

ユーザーを pages/login.js にリダイレクトします。これは、認証の背後にあるページに便利です。

import { useEffect } from "react"
import { useRouter } from "next/router"
// ここでは、ユーザーを取得して返します。
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>
}

URL オブジェクトの使用

URL オブジェクトは、next/link と同じように使うことができます。urlas パラメータの両方で動作します。

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

next/linkreplace prop と同様に、router.replace は履歴スタックに新しい URL エントリを追加するのを防ぎます。

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

クライアント側の遷移を高速化するために、ページをプリフェッチします。このメソッドは、next/link のないナビゲーションでのみ有効です。next/link はページのプリフェッチを自動的に行うからです。

これは製品版のみの機能です。Next.js は開発時にはページのプリフェッチを行いません。

router.prefetch(url, as)
  • url - プリフェッチする URL、つまり一致するページがあるパスです。
  • as - url 用のオプションのデコレーターです。Next.js 9.5.3 以前では、ダイナミックルートのプリフェッチに使用されていました。過去のドキュメントでは、どのように動作したかを確認できます。

使い方

例えば、ログインページがあり、ログイン後にユーザーをダッシュボードにリダイレクトするとします。この場合、以下の例のようにダッシュボードをプリフェッチすることで、より高速に遷移させることができます。

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({
        /* フォームデータ */
      }),
    }).then((res) => {
      // 既にプリフェッチされているダッシュボードページにクライアントサイドで高速に移行する
      if (res.ok) router.push("/dashboard")
    })
  }, [])
  useEffect(() => {
    // ダッシュボードページのプリフェッチ
    router.prefetch("/dashboard")
  }, [])
  return (
    <form onSubmit={handleSubmit}>
      {/* フォームフィールド */}
      <button type="submit">Login</button>
    </form>
  )
}

router.beforePopState

場合によっては(例えば、カスタム・サーバを使用している場合など)、popstate を聞いて、ルータがそれを処理する前に何かを行いたいことがあります。

router.beforePopState(cb)
  • cb - 入力される popstate イベントに対して実行される関数です。この関数は、イベントの状態を次のようなプロップを持つオブジェクトとして受け取ります。
    • url: String - 新しい状態のためのルートです。これは通常、ページの名前です。
    • as: String - ブラウザに表示される URL です。
    • options: Object - router.push によって送られる追加オプション

cbfalse を返した場合、Next.js のルーターは popstate を処理しませんので、その場合はあなたが処理することになります。ファイルシステムのルーティングを無効にするを参照してください。

使用方法

beforePopState を使って、次の例のようにリクエストを操作したり、SSR の更新を強制したりすることができます。

import { useEffect } from "react"
import { useRouter } from "next/router"
export default function Page() {
  const router = useRouter()
  useEffect(() => {
    router.beforePopState(({ url, as, options }) => {
      // 私はこの2つのルートだけを許可したいのです。
      if (as !== "/" && as !== "/other") {
        // SSRが悪いルートを404として表示する。
        window.location.href = as
        return false
      }
      return true
    })
  }, [])
  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 を再読み込みします。ブラウザの更新ボタンをクリックするのと同じです。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 }) - ルートが変更され始めたときに発生します。
  • routeChangeComplete(url, { shallow }) - ルートが完全に変更されたときに実行されます。
  • routeChangeError(err, url, { shallow }) - ルートの変更時にエラーが発生したとき、またはルートのロードがキャンセルされたときに発生します。
    • err.cancelled - ナビゲーションがキャンセルされたかどうかを示します。
  • beforeHistoryChange(url, { shallow }) - ブラウザの履歴を変更する前に発生します。
  • hashChangeStart(url, { shallow }) - ハッシュは変更されるが、ページは変更されない場合に発生します。
  • hashChangeComplete(url, { shallow }) - ハッシュが変更されたが、ページが変更されていない場合に発生します。

注:ここで url はブラウザに表示される URL で、basePath も含まれています。

使い方

例えば、ルーターイベント 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)
    // コンポーネントがアンマウントされた場合、アンサブスクライブ
    // イベントから `off` メソッドで脱退します。
    return () => {
      router.events.off("routeChangeStart", handleRouteChange)
    }
  }, [])
  return <Component {...pageProps} />
}

この例では、カスタムアプリpages/_app.js)を使用してイベントを購読していますが、アプリケーション内の任意のコンポーネントでルーターイベントを購読することができます。

ルーターイベントは、コンポーネントがマウントされたとき(useEffect または componentDidMount / componentWillUnmount)、またはイベントが発生したときに必須で登録する必要があります。

ルートのロードがキャンセルされた場合(例えば、2 つのリンクを連続して素早くクリックした場合など)、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)
    // コンポーネントがアンマウントされた場合、アンサブスクライブ
    // イベントから `off` メソッドで脱退します。
    return () => {
      router.events.off("routeChangeError", handleRouteChangeError)
    }
  }, [])
  return <Component {...pageProps} />
}

withRouter

useRouter が最適でない場合、withRouter でも同じrouterオブジェクトを任意のコンポーネントに追加することができます。

使用方法

import { withRouter } from 'next/router'
function Page({ router }) {
  return <p>{router.pathname}</p>
}
export default withRouter(Page)

TypeScript

クラスコンポーネントを withRouter で使用するには、コンポーネントがルーターの prop を受け入れる必要があります。

mport 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)

Discussion

ログインするとコメントできます