🦄

【Next.js】クエリパラメータを渡しつつ遷移先のURLには表示させない方法

2022/08/24に公開

Next.jsにおいて、クエリパラメータを渡しつつ遷移先のURLには表示させずに参照する方法です。
あまりこういったケースはないかもしれませんが、以前ハマってしまったので方法をふたつ書いておきます。

⛰ 目的

  • ページ遷移時にクエリパラメータをオブジェクトの形で渡したい
  • 遷移先のURLにはクエリパラメータを表示させたくない
  • 遷移先で渡されたクエリパラメータを参照したい
  • 遷移先へ直リンクした際はクエリパラメータは存在しないようにしたい

📦 前提

  • 特定の箇所で一時的に参照するため、Redux(などの状態管理ライブラリ)は使わない
  • /pages配下のファイル同士の受け渡しのため、Propsは使えない

💡 結論

  • Nextの<Link>コンポーネントで実現できる
  • router.push()で実現できる

Linkコンポーネントで実装する場合

/pages/first.tsx
/**
 * 遷移前のページ
 */
import Link from "next/link";

// 受け渡すクエリパラメータ
const query = {
  id: 1,
  name: "yakkun",
};

export default function First() {
  return (
    <Link href={{ pathname: "second", query: query }} as="second">
      <a>Secondへ遷移する</a>
    </Link>
  );
}
/pages/second.tsx
/**
 * 遷移後のページ
 */
import { useRouter } from "next/router";

export default function Second() {
  const router = useRouter();
  return (
    <ul>
      <li>id:{" " + router.query.id}</li>
      <li>name:{" " + router.query.name}</li>
    </ul>
  );
}

ブラウザでの挙動

  1. リンクをクリックして/secondへ遷移
  2. URLにクエリパラメータが表示されていない
  3. 値は参照できている
  4. 直リンクの際undefinedになっている(遷移時にクエリパラメータが渡されるため)

上記が確認できました。

router.push()で実装する場合

/pages/first.tsx
/**
 * 遷移前のページ
 */
import { useRouter } from "next/router";

// 受け渡すクエリパラメータ
const query = {
  id: 1,
  name: "yakkun",
};

export default function First() {
  const router = useRouter();

  const nextPage = () => {
    router.push({ pathname: "second", query: query }, "second");
  };

  return <button onClick={() => nextPage()}>secondへ遷移する</button>;
}
/pages/second.tsx
/**
 * 遷移後のページ
 */
import { useRouter } from "next/router";

export default function Second() {
  const router = useRouter();
  return (
    <ul>
      <li>id:{" " + router.query.id}</li>
      <li>name:{" " + router.query.name}</li>
    </ul>
  );
}

ブラウザでの挙動

まぁ、さっきと同じです。

📖 解説

Linkの解説

Nextが提供している<Link>コンポーネントは、通常href={"/hoge/huga"}のようにパスを指定します。
ただこのhrefはオブジェクトも受け付けており、pathname, queryというキーが使用できます。
それぞれ名称の通りパスとクエリパラメータを渡すことができます。

そして、今回重要なのはasというオプションです。
asには遷移先で表示するURLを渡すことができます。

/pages/first.tsx
// 省略
    <Link href={{ pathname: "second", query: query }} as="second">
      <a>Secondへ遷移する</a>
    </Link>
  );
}

つまり、どんなクエリパラメータを渡そうともasにより指定されたパスパラメータが遷移先のURLに表示されるという仕組みです。

上記の例では遷移先のURLは/secondとなります。

router.push()の解説

Nextの<Link>コンポーネントと同様に、SPAの挙動を取るrouter.push()でも同様の実装ができます。

/pages/first.tsx
// 省略
const router = useRouter();

const nextPage = () => {
    router.push({ pathname: "second", query: query }, "second");
  };

  return <button onClick={() => nextPage()}>secondへ遷移する</button>;
}

関数nextPageを定義し、<button>タグのonClickイベントに渡しました。

nextPageではrouter.push()にふたつの引数を渡しています。

第一引数にはurlを受け付けるのですが、<Link>同様オブジェクトでpathnamequeryを渡すことができます。

そして、第二引数には<Link>コンポーネントにおけるasに相当する文字列を渡すことができ、遷移先のURLにどう表示されるかを指定することができます。

🖋 まとめ

ふたつとも同じ挙動を取るためどちらでも実現できます。

ただ<Link>コンポーネントにはクリックイベントを指定できないため、遷移と同時に値を取得する処理などを挟む場合はrouter.push()を使うとよいと思います。

また、非表示であれクエリパラメータはrouterに格納されているため、遷移先で参照するにはuseRouter()が必要になり、router.query.{hoge}の形を取ることになります。

🦄 おわり

今回はクエリパラメータを渡しつつ遷移先のURLに表示させない方法をご紹介しました。

本来であればクエリパラメータやasは動的ルーティングで活躍すると思うのですが、こういった使い方もできるよ〜というお話でした。

それではまた。

📘 参考

Discussion