Lang x Lang

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;

useRouterReact Hook であり、それはクラスの中で使用することはできません。あなたはwithRouterを使用するか、クラスを component の関数内に置くことができます。

router object

以下は、useRouterwithRouterの両方が返すrouter object の定義です:

  • pathname: String - 現在の route ファイルの path で、/pagesの後に来ます。したがって、basePathlocaleおよび末尾のスラッシュ(trailingSlash: true)は含まれていません。
  • query: Object - クエリー string が object にパースされ、dynamic routeのパラメータを含みます。ページがServer-side Renderingを使用していない場合、プレ rendering 中に空のオブジェクトになります。{}が default です。
  • asPath: String - ブラウザで表示される path で、検索 params を含み、trailingSlash設定を尊重しています。 basePathlocaleは含まれていません。
  • 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 側で更新され、使用可能になっているかどうか。 useEffectMethod 内でのみ使用すべきであり、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です。
  • 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 が変更されない限りアンマウントされないからです。

pages/[slug].js
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 を使用することができます。これは、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

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

cbfalseを返す場合、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

routerobject で利用できる特定の方法は 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);

当社サイトでは、Cookie を使用しています。各規約をご確認の上ご利用ください:
Cookie Policy, Privacy Policy および Terms of Use