router.pushとは?Vue/Nuxtでの基本的な使い方とオプションの詳細な説明
はじめに
シングルページアプリケーション(SPA)において、画面間の遷移はユーザー体験の根幹をなします。Vue.jsやNuxt.jsのようなモダンなJavaScriptフレームワークでは、この画面遷移、つまりルーティングは非常に洗練された方法で実現されています。特に、プログラム的に任意のタイミングで画面遷移を実行したい場合に中心的な役割を果たすのが、本記事の主題である router.push
メソッドです。
この記事では、Vue RouterおよびNuxt.jsにおける router.push
メソッドについて、その基本的な概念から詳細な使い方、利用可能なオプション、そして注意点に至るまで、深く掘り下げて解説します。約5000語をかけて、あなたが router.push
を完全に理解し、日々の開発で自信を持って使いこなせるようになることを目指します。
まずは、なぜ router.push
が必要なのか、クライアントサイドルーティングとは何か、そしてVue Routerの基本的な仕組みから見ていきましょう。
クライアントサイドルーティングとは?
従来のウェブアプリケーションでは、ページ間の移動はブラウザがサーバーに新しいHTMLファイルをリクエストすることで行われていました。これはページ全体のリロードを伴うため、特にインタラクティブなアプリケーションではユーザー体験を損なう要因となり得ます。
一方、クライアントサイドルーティングでは、ブラウザは最初に一度だけHTMLファイルを読み込み、その後の画面の切り替えはJavaScriptによって動的に行われます。URLの変更は History API
( pushState
, replaceState
など) を利用してブラウザ履歴を操作することで行われ、実際のページリロードは発生しません。これにより、ネイティブアプリケーションのような滑らかで素早い画面遷移が可能になります。
Vue.jsにおいては、このクライアントサイドルーティングを実現するための公式ライブラリが Vue Router です。
Vue Routerの役割
Vue Routerは、Vue.jsアプリケーションにおけるルーティングを管理するためのデファクトスタンダードです。
- ルート定義: どのURLパスがどのVueコンポーネントに対応するかを定義できます。
- ナビゲーション: プログラム的または宣言的に、異なるルートへ移動するための手段を提供します。
- ナビゲーションガード: ルート遷移の前後で処理を挟み込む仕組みを提供し、認証チェックやデータ取得などを行えます。
- ブラウザ履歴管理:
History API
を抽象化し、ブラウザの戻る/進むボタンに対応します。
router.push
の位置づけ
Vue Routerを使って異なるルートへナビゲートする方法は主に二つあります。
- 宣言的ナビゲーション:
router-link
コンポーネントを使用する方法です。HTMLの<a href="...">
タグに似ていますが、ページリロードなしにナビゲートします。主に固定のリンクを設置する場合に用います。
vue
<template>
<router-link to="/about">Aboutページへ</router-link>
<router-link :to="{ name: 'user', params: { userId: 123 } }">ユーザー123の詳細へ</router-link>
</template> - プログラム的ナビゲーション: JavaScriptのコードから
router.push
などのメソッドを呼び出してナビゲートする方法です。ユーザーのアクション(ボタンクリック、フォーム送信など)の結果や、非同期処理の完了後に動的に遷移先を決定したい場合に用います。
router.push
は、このプログラム的ナビゲーションの中核をなすメソッドです。特定のイベントが発生した後に、指定したルートへユーザーを誘導するために使用します。
Vue Routerの基本的なセットアップ
router.push
の使い方を理解するためには、まずVue Routerの基本的なセットアップを知っておく必要があります。ここではVue 3とVue Router 4を前提に簡単な例を示します。
-
インストール:
bash
npm install vue-router@4 -
ルーターインスタンスの作成:
src/router/index.js
(例)“`javascript
import { createRouter, createWebHistory } from ‘vue-router’;
import HomeView from ‘../views/HomeView.vue’;
import AboutView from ‘../views/AboutView.vue’;
import UserView from ‘../views/UserView.vue’; // 仮のコンポーネントconst router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: ‘/’,
name: ‘home’,
component: HomeView
},
{
path: ‘/about’,
name: ‘about’,
component: AboutView
},
{
path: ‘/users/:id’, // 動的セグメント
name: ‘user’,
component: UserView
}
]
});export default router;
``
createWebHistory
*: ブラウザ履歴を
History APIで管理するためのヒストリーモードです。サーバー設定によってはフォールバックが必要です。
routes`: ルート定義の配列です。各オブジェクトはパス、名前、コンポーネントなどを指定します。
* -
Vueアプリケーションへの組み込み:
src/main.js
(例)“`javascript
import { createApp } from ‘vue’;
import App from ‘./App.vue’;
import router from ‘./router’;const app = createApp(App);
app.use(router);
app.mount(‘#app’);
“` -
ルートの表示場所の指定:
src/App.vue
(例)“`vue
``
router-view` は、現在のURLに対応するコンポーネントが表示されるプレースホルダーです。
これで基本的なルーティングの準備ができました。アプリケーションのコンポーネント内で、this.$router
(Options API) または useRouter()
(Composition API) を通じてルーターインスタンスにアクセスし、router.push
メソッドを呼び出すことでプログラム的な画面遷移を実行できます。
“`vue
ホーム
``
router.push
上記の例では、ボタンクリックというイベントをトリガーにを呼び出し、指定したルートへナビゲートしています。これが
router.push` の最も基本的な使い方です。
router.push
とは?詳細解説
router.push(location)
は、Vue Routerインスタンスのメソッドであり、プログラム的に新しいURLへ移動するために使用されます。名前の通り、ブラウザの履歴スタックに新しいエントリを「プッシュ」することで機能します。これはブラウザの戻るボタンで前のページに戻れることを意味します。
技術的には、router.push
はブラウザの History API
の history.pushState()
メソッドをラップしています。history.pushState()
は、ページの再読み込みなしにブラウザの履歴に新しい状態を追加し、URLを変更することができます。Vue Routerはこれを利用して、URLの変更と対応するコンポーネントのレンダリングを同期させています。
router.replace
との違い
router.push
と非常によく似たメソッドに router.replace(location)
があります。両者の唯一かつ重要な違いは、履歴スタックへの影響です。
router.push
: 現在のURLの上に新しいURLを追加します。history.pushState()
に対応します。戻るボタンで前のページに戻れます。router.replace
: 現在のURLを新しいURLで置き換えます。history.replaceState()
に対応します。戻るボタンを押しても、置き換えられる前のページには戻れません。
どちらを使うべきかは、ユースケースによって異なります。
router.push
を使う場合:- 通常のナビゲーション(例: リンクをクリックして別のページへ移動)。
- ユーザーが前のページに戻ることを期待する場合。
router.replace
を使う場合:- ログイン後のリダイレクト(ログインページに戻れないようにする)。
- エラーページへのリダイレクト(エラー発生前のページに戻れないようにする)。
- フォーム送信後など、前の状態に戻るのが不自然な場合。
- フィルタリングやソートなど、URLパラメータの変更が頻繁に行われるが、ブラウザ履歴を汚したくない場合(履歴を1つにまとめたい)。
router.push
は履歴スタックに追加されるため、ユーザーが「戻る」操作で元のページに戻ることができます。ほとんどのナビゲーションはこの挙動を期待するため、特別な理由がない限り router.push
を使うのが一般的です。
router.push
の基本的な使い方と引数
router.push
メソッドには、ナビゲーション先を指定するために主に二つの形式の引数を渡すことができます。
- パス文字列: シンプルなパスを指定します。
- ロケーションオブジェクト: より詳細なナビゲーション情報をオブジェクト形式で指定します。こちらが推奨される形式です。
1. パス文字列で指定する
最も簡単な方法です。
javascript
router.push('/users/123'); // 絶対パス
router.push('profile'); // 相対パス (現在のルートからの相対パス)
* 絶対パス: /
から始まるパスを指定します。常にアプリケーションのルートからのパスとして解釈されます。
* 相対パス: /
から始まらないパスを指定します。現在のルート ($route.path
) からの相対パスとして解釈されます。例えば、/users/123
にいるときに router.push('profile')
を呼び出すと、/users/profile
にナビゲートされます。相対パスは、ネストされたルーティングや、現在のルートに基づいて動的にパスを決定したい場合に便利です。
パス文字列形式はシンプルですが、動的なパラメータやクエリパラメータを扱う場合には、文字列連結などで複雑になりがちです。また、ルート定義のパスを変更した場合に、それを参照しているすべての文字列を修正する必要があり、メンテナンス性が低下する可能性があります。
2. ロケーションオブジェクトで指定する (推奨)
ロケーションオブジェクトは、ナビゲーション先の情報を構造化されたオブジェクトとして渡す方法です。これにより、パス、名前、パラメータ、クエリなどを明確に指定できます。
基本的なロケーションオブジェクトの構造は以下のようになります。
“`javascript
{
// 以下のいずれか一つ(または両方、ただし name が優先されることが多い)
path: ‘/path/to/go’,
name: ‘routeName’,
// オプション
params: { id: ‘123’ }, // 動的セグメントのパラメータ
query: { search: ‘vue’, page: 1 }, // クエリパラメータ
hash: ‘#section’, // ハッシュフラグメント
replace: true, // router.replace と同じ効果にするか
force: true, // Vue Router v4以降: 同一パスでも強制ナビゲーションするか
state: { data: ‘…’, history: ‘…’ } // Vue Router v4以降: History API の state
}
“`
それぞれのプロパティについて、以降で詳しく解説します。
例:
-
パス指定:
javascript
router.push({ path: '/about' });
これはrouter.push('/about')
と同じです。 -
名前付きルート指定 (推奨):
javascript
router.push({ name: 'user', params: { id: 123 } });
ルート定義でname: 'user'
と定義されていて、パスが/users/:id
の場合、/users/123
にナビゲートされます。名前を使う利点は、URLパスが変わってもname
を変更しなければコードを修正する必要がない点です。動的なパラメータ (:id
) はparams
オブジェクトで指定します。 -
クエリパラメータ指定:
javascript
router.push({ path: '/search', query: { q: 'vue', sort: 'date' } });
// または名前付きルートで
router.push({ name: 'searchPage', query: { q: 'vue', sort: 'date' } });
// => /search?q=vue&sort=date にナビゲート
query
オブジェクトで指定されたキーと値は、URLの?
以降のクエリ文字列に変換されます。 -
ハッシュフラグメント指定:
javascript
router.push({ path: '/article', hash: '#comments' });
// または名前付きルートで
router.push({ name: 'articlePage', params: { id: 456 }, hash: '#comments' });
// => /article#comments または /articles/456#comments にナビゲート
hash
プロパティで指定された文字列は、URLの#
以降に追加されます。
ロケーションオブジェクトを使うことで、ナビゲーションの意図が明確になり、コードの可読性とメンテナンス性が向上します。特に動的なパラメータやクエリパラメータを扱う場合は、常にロケーションオブジェクト形式を使用することが強く推奨されます。
ロケーションオブジェクトの詳細なオプション
ロケーションオブジェクトの各プロパティについて、さらに詳しく見ていきましょう。
path
ナビゲーション先のパスを文字列で指定します。
javascript
router.push({ path: '/settings/profile' });
* /
から始まる絶対パスと、現在のルートからの相対パスを指定できます。
* ロケーションオブジェクトに path
と name
の両方を指定した場合、通常 name
が優先されます。ただし、params
を指定する場合は注意が必要です(後述)。
* path
に動的セグメントを含む文字列を直接指定することも可能ですが、params
と組み合わせて使う場合は name
を使う方が意図が明確になります。例: router.push({ path: '/users/' + userId })
より router.push({ name: 'user', params: { id: userId } })
の方が良い。
name
ナビゲーション先のルートの名前を文字列で指定します。
javascript
// ルート定義: { path: '/products/:id', name: 'productDetail', component: ProductView }
router.push({ name: 'productDetail', params: { id: 789 } });
// => /products/789 にナビゲート
* ルート定義で name
プロパティを指定しておく必要があります。
* 動的なルートセグメント (:id
, :slug
など) が含まれるルートに名前でナビゲートする場合、必ず params
オブジェクトで対応するパラメータの値を指定する必要があります。パラメータが不足している場合、ナビゲーションが失敗したり、予期しないURLになったりすることがあります。
* 名前付きルートはパスの変更に強く、リファクタリングが容易になります。
注意点: path
と params
の組み合わせ
ロケーションオブジェクトで path
プロパティと params
プロパティを同時に使用する場合、特に絶対パスを指定している場合は注意が必要です。
Vue Router 4のドキュメントによれば、path
を使用する場合、params
は無視されるべきではないとされていますが、path
にはパラメータをプレースホルダーとして含めることができないため、params
の値がURLに反映されない挙動になることが多いです。
推奨される書き方:
-
動的なパラメータを含むパスにナビゲートしたい場合は、必ず
name
とparams
を組み合わせて使用 してください。
javascript
// ✅ 推奨: 名前付きルートとparams
router.push({ name: 'user', params: { id: 123 } }); // ルート定義: { path: '/users/:id', name: 'user', ... } -
動的なパラメータを含まないパスにナビゲートする場合、
path
またはname
のどちらか一方を使用します。
javascript
// ✅ OK: path だけ
router.push({ path: '/about' });
// ✅ OK: name だけ (params なし)
router.push({ name: 'about' }); // ルート定義: { path: '/about', name: 'about', ... } -
path
とparams
を同時に指定するのは避けてください。特に絶対パスで。相対パスの場合は挙動が異なることがありますが、混乱を避けるためにもname
+params
がベストプラクティスです。
params
動的なルートセグメント (/users/:id
) に渡すパラメータをオブジェクト形式で指定します。
javascript
router.push({ name: 'article', params: { category: 'vue', slug: 'router-push' } });
// ルート定義: { path: '/articles/:category/:slug', name: 'article', ... }
// => /articles/vue/router-push にナビゲート
* params
は基本的に name
と組み合わせて使用します。path
と一緒に使う場合の注意点は前述の通りです。
* params
の値は、URLの該当セグメントに埋め込まれ、自動的にURLエンコードされます。
* 対象ルートに定義されていないパラメータを params
オブジェクトに含めても、通常は無視されます。
* パラメータの値は基本的に文字列として扱われます。数値やその他の型の値を渡しても、文字列に変換されてURLに埋め込まれます。
* $route.params
からアクセスできます。例えば、/users/123
ルートのコンポーネント内で this.$route.params.id
(Options API) または route.params.id
(Composition API, useRoute()
で取得) とすることで 123
を取得できます。
params にオブジェクトや配列を渡す場合
Vue Routerは params
の値としてオブジェクトや配列を直接URLに埋め込むことはできません。これらの値は文字列に変換されるか、エラーの原因となる可能性があります。複雑なデータ構造を渡したい場合は、クエリパラメータ (query
) を利用するか、状態管理ツール、またはナビゲーションガードの meta
フィールドなどを検討する必要があります。
query
URLのクエリパラメータ (?key1=value1&key2=value2
) をオブジェクト形式で指定します。
javascript
router.push({ path: '/products', query: { page: 2, sort: 'price', filter: ['red', 'blue'] } });
// => /products?page=2&sort=price&filter=red&filter=blue にナビゲート (デフォルト挙動)
* path
または name
と組み合わせて使用します。
* query
オブジェクトのキーと値は、URLの ?
以降に自動的に追加され、URLエンコードされます。
* 値には文字列、数値、真偽値などを指定できます。null
や undefined
は通常クエリパラメータとして追加されません。
* 配列の扱い: デフォルトでは、配列 (filter: ['red', 'blue']
) は同じキーを繰り返す形式 (?filter=red&filter=blue
) でエンコードされます。これは URLSearchParams
のデフォルトの挙動です。もし ?filter[]=red&filter[]=blue
のような形式にしたい場合は、qs
のようなライブラリを使って自分でクエリ文字列を生成し、それを path
または name
と共にロケーションオブジェクトの path
に含める必要がありますが、これは稀なケースです。通常はVue Routerのデフォルト挙動で十分です。
* $route.query
からアクセスできます。例えば、上記の例の場合、/products
ルートのコンポーネント内で $route.query.page
は 2
(文字列)、$route.query.sort
は 'price'
、$route.query.filter
は ['red', 'blue']
(配列) となります。$route.query
の値は常に文字列または文字列の配列になります。
hash
URLのハッシュフラグメント (#section
) を文字列で指定します。
javascript
router.push({ path: '/faq', hash: '#general-questions' });
// => /faq#general-questions にナビゲート
* path
または name
と組み合わせて使用します。
* hash
プロパティの値は、URLの #
以降に自動的に追加され、URLエンコードされます。#
自体は指定する必要はありません。
* 通常、ページ内の特定要素へのジャンプに使用されます(ただし、Vue Routerのデフォルトのスクロール挙動設定に影響されます)。
* $route.hash
からアクセスできます。例えば、上記の例の場合、/faq
ルートのコンポーネント内で $route.hash
は '#general-questions'
となります。
replace
真偽値 (true
または false
) で指定します。true
に設定すると、このナビゲーションは router.push
としてではなく、router.replace
として実行されます。
javascript
// ログイン成功後にダッシュボードへリダイレクトし、ログインページに戻れないようにする
router.push({ name: 'dashboard', replace: true });
* デフォルトは false
です。
* 履歴スタックに新しいエントリを追加せず、現在のエントリを置き換える効果があります。
force
(Vue Router v4以降)
真偽値 (true
または false
) で指定します。ナビゲーション先のロケーションが現在のロケーションと全く同じである場合でも、強制的にナビゲーションを実行するかどうかを制御します。
javascript
// 現在のページをリロードするような効果を得たい場合など
router.push({ path: router.currentRoute.value.fullPath, force: true });
* デフォルトは false
です。
* 通常、Vue Routerは現在のロケーションと全く同じロケーションへのナビゲーションリクエストを無視します。force: true
を指定すると、このデフォルトの挙動が overridden され、ナビゲーションパイプラインが再実行されます(ただし、コンポーネントの再利用設定によってはコンポーネント自体は再作成されないことがあります)。
* 同じルートのままクエリパラメータだけを変更したい場合などに force: true
が役立つことがあります。しかし、通常は replace: true
を使う方が履歴管理の観点から自然です。force: true
が必要なケースは比較的少ないかもしれません。
state
(Vue Router v4以降)
history.state
に保存する任意のカスタムオブジェクトを指定します。
javascript
router.push({
path: '/items',
query: { id: 123 },
state: { fromList: true, scrollY: window.scrollY }
});
* このオブジェクトはブラウザ履歴のエントリに関連付けられます。
* ページをリロードしても失われません(ただし、セッションストレージなどに永続化されるわけではありません)。
* $route.state
(Vue Router v4以降) からアクセスできます。ただし、$route.state
はリアクティブではありません。
* 主に、ユーザーが戻る/進むボタンで移動した際に、元のページの状態(例: スクロール位置、フィルタリングオプションなど)を復元するために使用されることがあります。
* params
や query
とは異なり、URLの一部としては表示されません。機密情報や巨大なデータを含めるべきではありません。
ナビゲーションの完了を待つ (async
/await
)
router.push
メソッドは、Vue Router v3.1以降では Promise を返します。これにより、ナビゲーション処理が完了(成功または失敗)するのを待ってから次の処理を実行することができます。これは非同期処理 (async
/await
) と組み合わせることで非常に強力になります。
Promiseは以下のいずれかの理由で解決または拒否されます。
- 解決 (
resolve
):- ナビゲーションが正常に完了した場合。
- ナビゲーションが同じ場所で中断された場合 (
force: false
の場合)。 - ナビゲーションガードから
next(false)
が呼び出された場合。
- 拒否 (
reject
):- ナビゲーションガードからエラーがスローされた場合。
- ナビゲーションが新しいナビゲーションによって中断された場合 (例:
router.push
を連続で呼び出した場合)。
基本的な使い方:
javascript
async goToDashboard() {
try {
await router.push({ name: 'dashboard' });
console.log('ナビゲーションが完了しました。');
// ナビゲーション後の追加処理 (例: 特定要素までスクロール)
} catch (err) {
if (err instanceof Error && err.name === 'NavigationDuplicated') {
console.warn('同じ場所へのナビゲーションは無視されました:', err);
// または別のエラーハンドリング
} else {
console.error('ナビゲーション中にエラーが発生しました:', err);
// エラーページへリダイレクトするなど
// router.replace({ name: 'errorPage' });
}
}
}
ユースケース:
-
ナビゲーション後のスクロール制御:
デフォルトのスクロール挙動とは別に、特定のナビゲーション後に特定の要素までスクロールしたい場合。
javascript
async goToArticle(articleId) {
await router.push({ name: 'article', params: { id: articleId } });
// ナビゲーション完了後、記事本文が表示されたらスクロールする
// (DOMが更新されていることを保証する必要がある)
const commentsSection = document.getElementById('comments');
if (commentsSection) {
commentsSection.scrollIntoView();
}
}
(注: コンポーネントが表示されてからDOM要素が存在することを確認する必要があります。$nextTick
やライフサイクルフックを使うことも検討) -
ナビゲーションが成功したことを確認してから次のアクション:
例えば、フォームを送信し、成功したら特定のページに移動し、その移動が完了してから成功メッセージを表示するなど。 -
ナビゲーション中断・エラー時のハンドリング:
例えば、ログインが必要なページへ遷移しようとしたが、ナビゲーションガードでログインページへリダイレクトされた場合 (next(false)
またはリダイレクト先へのrouter.push
がガード内で実行された場合)、元のrouter.push
は中断として解決されます。エラーが発生した場合(例: ルートが見つからない、ナビゲーションガードでエラーがスローされたなど)は拒否されます。これらの状況を適切にハンドリングすることで、より堅牢なアプリケーションを作成できます。
ナビゲーションが中断された場合の Promise の解決値や、発生しうるエラー (NavigationFailure
型のインスタンス、特に NavigationDuplicated
) については、Vue Routerの公式ドキュメントで詳細を確認することをお勧めします。
router.push
とナビゲーションガード
Vue Routerのナビゲーションガードは、ルート遷移のパイプラインにフックして処理を実行する強力な機能です。router.push
を含むすべてのプログラム的ナビゲーションリクエストも、これらのガードを通過します。
ナビゲーションガードには、グローバルガード (beforeEach
, beforeResolve
, afterEach
)、ルートごとのガード (beforeEnter
)、そしてコンポーネント内ガード (beforeRouteEnter
, beforeRouteUpdate
, beforeRouteLeave
) があります。
ガードの中でナビゲーションを制御する場合、通常は next()
関数を使用します。
next()
: ナビゲーションを継続します。next(false)
: 現在のナビゲーションを中止し、URLも変更しません。next('/')
またはnext({ path: '/...' })
またはnext({ name: '...' })
: 指定したロケーションにリダイレクトします。現在のナビゲーションは中止され、新しいナビゲーションが開始されます。next(error)
: ナビゲーションを中止し、エラーハンドラーにエラーを渡します。
ガード内で router.push
を使う場合
通常、ナビゲーションガードの中でリダイレクトを行いたい場合は next({ ... })
を使用することが推奨されます。なぜなら next()
は現在のナビゲーションパイプラインの一部として処理されるため、ガードの実行順序などが保証されやすいからです。
しかし、特定の非同期処理の完了を待ってからリダイレクトしたい場合など、ガードの処理が複雑になるケースでは、ガード内で現在のナビゲーションを中止し (next(false)
または引数なしの next()
※非同期ガードの場合)、その後に router.push
を呼び出して新しいナビゲーションを開始するというパターンも考えられます。
例: 認証チェックミドルウェア(Nuxtを意識した例)
“`javascript
// middleware/auth.js (Nuxtのミドルウェアとして使用する場合)
export default async function({ route, redirect, $auth }) { // Nuxt context にアクセス
// または Composition API で useRoute, useRouter, useAuth などを使用
// ログインが必要なルートかチェック
if (route.meta.requiresAuth && !$auth.loggedIn) {
// ログインしていなければログインページへリダイレクト
// Nuxtでは redirect ヘルパーが推奨されるが、router.push を使うなら
// const router = useRouter(); // または this.$router (Options API)
// await router.push({ name: ‘login’, query: { redirect: route.fullPath } });
// return false; // 実際には useRouter().push だけでナビゲーションが始まるので、return は不要か、または Promise を返す必要あり
// ここは Nuxt の redirect ヘルパーを使うのが一般的
redirect({ name: 'login', query: { redirect: route.fullPath } });
}
}
``
beforeEach
上記の例はNuxtのミドルウェアの文脈ですが、Vue Routerのグローバルガード () でも同様の考え方でリダイレクトを実装できます。ただし、ガード内で
router.pushを使う際は、無限リダイレクトに陥らないよう注意が必要です。例えば、ログインページ自体にいるのにログインページへリダイレクトしようとすると無限ループになります。これは
nextにリダイレクト先を渡す場合も同じですが、
router.pushの場合はガードパイプラインの外で新たなナビゲーションが開始されるため、デバッグが少し難しくなる可能性があります。特別な理由がない限り、ガード内でのリダイレクトは
next({ … })` を優先するのが安全です。
Nuxt.js における router.push
Nuxt.jsは、Vue.jsをベースにしたフレームワークであり、Vue Routerを内部で使用しています。Nuxtの pages
ディレクトリ構造に基づいたファイルシステムルーティングは、裏側でVue Routerのルート定義に変換されています。
Nuxt環境で router.push
を使用する方法は、基本的に標準のVueアプリケーションと同じですが、Nuxt特有のアクセス方法や考慮事項があります。
router.push
へのアクセス方法
-
Vue コンポーネント内:
- Options API:
this.$router.push(...)
- Composition API:
import { useRouter } from 'vue-router'; const router = useRouter(); router.push(...)
- Options API:
-
Plugins, Middleware,
asyncData
,fetch
, Server Middleware:
Nuxtのこれらの機能は、クライアントサイドとサーバーサイドの両方で実行される可能性があります。ルーターへのアクセス方法は実行環境によって異なります。- クライアントサイド:
context.app.router.push(...)
または Composition API のuseRouter()
(Nuxt 3) - サーバーサイド: サーバーサイドでは直接的なDOM操作やブラウザ履歴操作はできません。サーバーサイドでリダイレクトを行う場合は、Nuxt Context の
redirect
ヘルパー関数を使用します。
javascript
// Nuxt 2 Middleware (例)
export default function ({ req, redirect, route }) {
if (req) { // サーバーサイドの場合
// クライアントサイドでリダイレクトする場合は router.push を使うこともできるが、
// サーバーサイドレンダリング時は redirect が必要
if (!isAuthenticated(req) && route.path !== '/login') {
redirect('/login'); // HTTPリダイレクト
}
} else { // クライアントサイドの場合
if (!isAuthenticatedClient() && route.path !== '/login') {
// クライアントサイドでの非同期処理後など
// context.app.router.push('/login');
// または Vue コンポーネントなら this.$router.push('/login'); / useRouter().push('/login');
}
}
}
Nuxt 3 では、Composition API とより構造化されたコンテキストアクセスが推奨されます。“`javascript
// Nuxt 3 Plugin (例)
import { defineNuxtPlugin } from ‘#app’;
import { useRouter } from ‘vue-router’;export default defineNuxtPlugin(nuxtApp => {
// クライアントサイドでのみ実行される処理
if (process.client) {
const router = useRouter();
// 何らかのイベントで router.push(…) を呼び出す
// 例: nuxtApp.vueApp.config.globalProperties.$eventBus.on(‘redirect’, (path) => {
// router.push(path);
// });
}
});
“`asyncData
やfetch
でデータを取得した結果に基づいてリダイレクトしたい場合も、クライアントサイドでの実行であればthis.$router.push
(Options API) またはuseRouter().push
(Composition API)、サーバーサイドでの実行であればredirect
ヘルパーを使用します。 - クライアントサイド:
NuxtSpecificな考慮事項
- サーバーサイドレンダリング (SSR):
router.push
はブラウザのHistory API
を利用するため、サーバーサイドでは実行できません。サーバーサイドでリダイレクトしたい場合は、Nuxt Context のredirect(path)
ヘルパー関数を使います。これはHTTPステータスコード302と共にブラウザへリダイレクト指示を送ります。 - ミドルウェア: ミドルウェアはクライアントサイドとサーバーサイドの両方で実行されます。ミドルウェア内で条件付きリダイレクトを行う場合は、実行環境を判別し、適切な方法(クライアントなら
router.push
またはnext({ ... })
、サーバーならredirect
) を使用する必要があります。 - ファイルシステムルーティングと名前付きルート: Nuxtの
pages
ディレクトリでファイルやディレクトリを作成すると、Vue Routerのルート定義が自動生成されます。ディレクトリやファイル名に対応する名前付きルートも自動で生成されるため、router.push({ name: '...' })
を使うことで、ファイルパスの変更に強いナビゲーションを記述できます。例えば、pages/users/_id.vue
は通常name: 'users-id'
という名前のルートになります(ファイルシステムに基づいた命名規則)。
実践的なシナリオと例
router.push
は様々な場面で利用されます。いくつか代表的なシナリオを見てみましょう。
1. ログイン成功後のリダイレクト
ユーザーがログインフォームを送信し、認証に成功した場合、元のページやダッシュボードページにリダイレクトするのが一般的です。この際、ログインページに戻れないようにするために replace: true
を使うことが多いです。
“`vue
``
/login?redirect=/protected
この例では、ログインが必要なページにアクセスしようとしてログインページにリダイレクトされた場合 (),
route.query.redirect` を利用してログイン後の遷移先を決定しています。
2. フォーム送信後の別ページへの遷移
新しいリソースを作成するフォーム(例: ブログ記事作成)を送信した後、作成されたリソースの詳細ページへ遷移させるシナリオです。
“`vue
``
await router.push` を使うことで、APIコールが成功し、かつ、その後のナビゲーションが完了したことを確認してから次の処理を実行できます。
3. 検索結果ページへのクエリパラメータ付き遷移
検索フォームから検索を実行し、結果を別ページに表示する際に、検索キーワードなどをクエリパラメータとしてURLに含めることで、ページの共有やブックマークを可能にします。
“`vue
``
push
ユーザーが検索を実行するたびに履歴スタックに新しいエントリが追加され、ブラウザの戻るボタンで前の検索結果に戻れるようにが使用されています。もし履歴を汚したくない場合は
replace: true` を使用することも考えられます。
4. テーブルの行クリックによる詳細ページへの遷移 (動的パラメータ)
一覧表示されたデータの各項目をクリックすると、その項目の詳細ページへ移動するシナリオは非常に一般的です。
“`vue
ID | 名前 | … |
---|---|---|
{{ item.id }} | {{ item.name }} | … |
``
itemId
動的なを
paramsオブジェクトとして渡し、名前付きルート
itemDetailを利用しています。これにより、
/items/1,
/items/2` のように異なるURLにナビゲートされます。
5. タブ切り替えやフィルタリングでのクエリ/ハッシュ更新
同じコンポーネント内で表示内容を切り替える(例: タブ表示、リストのフィルタリング/ソート)際に、その状態をURLのクエリパラメータやハッシュで表現することがあります。この場合、ページ自体はリロードせず、URLだけを変更し、かつブラウザ履歴を汚したくない(戻るボタンで前のタブやフィルタに戻る必要がない)ことが多いです。このようなケースでは replace: true
を使うことが有効です。
“`vue
``
replace: true` を使うことで、ブラウザ履歴には常に最新のタブ状態のみが記録されるようにしています。
この例では、タブを切り替えるたびに現在のURLのクエリパラメータを更新し、その際に
router.push
利用時の注意点とベストプラクティス
router.push
は非常に柔軟で強力ですが、正しく使用しないと予期しない挙動やバグにつながる可能性があります。以下の点に注意し、ベストプラクティスを心がけましょう。
- 常にロケーションオブジェクトを使用する (特に名前付きルート): パス文字列での指定はシンプルですが、動的なパラメータやクエリパラメータを扱う場合は、可読性、メンテナンス性、堅牢性の観点からロケーションオブジェクトを使用することを強く推奨します。特に名前付きルートは、URL構造の変更に強いコードを書く上で不可欠です。
params
はname
と一緒に使う: 動的なルートパラメータ (/users/:id
) に値を渡す場合は、必ずname
プロパティでルート名を指定し、params
プロパティでパラメータを渡してください。path
とparams
を同時に使う、特に絶対パスで使うのは避けてください。query
は単なる文字列として扱われることを理解する:query
オブジェクトの値はURLエンコードされて文字列としてURLに追加されます。複雑なオブジェクトや配列をそのまま渡そうとせず、必要に応じて文字列化(例: JSON.stringify)するか、より適切な方法(state
、状態管理、API経由でのデータ取得など)を検討してください。ただし、配列はデフォルトで特定の形式にエンコードされます。- ナビゲーションガード内での無限ループに注意: ナビゲーションガード内で
router.push
やnext({ ... })
を使用してリダイレクトを行う場合、リダイレクト先のルートでも同じガードが実行され、再び同じ条件でリダイレクトがトリガーされると無限ループに陥ります。リダイレクト先のルートではそのガードをスキップする条件を追加するなど、無限ループを防ぐロジックを必ず組み込んでください。 - サーバーサイドレンダリング (SSR) 環境での注意: NuxtなどのSSRフレームワークでは、
router.push
はクライアントサイドでのみ有効です。サーバーサイドでリダイレクトが必要な場合は、フレームワークが提供する適切な手段(Nuxtのredirect
ヘルパーなど)を使用してください。 - エラーハンドリングの重要性:
router.push
は Promise を返すので、async
/await
とtry...catch
ブロックを組み合わせて、ナビゲーションが失敗したり中断されたりした場合のエラーを適切に処理することが重要です。これにより、ユーザーにエラーを通知したり、フォールバック処理を実行したりできます。特に同じ場所へのナビゲーションによるNavigationDuplicated
エラーは頻繁に発生しうるため、適切に処理することをお勧めします。 - 同じルート、同じパラメータ、同じクエリへのナビゲーション: デフォルトでは、Vue Routerは既にいる場所へのナビゲーションリクエストを無視します。これは不必要なナビゲーションを防ぐための挙動です。もし何らかの理由で同じ場所へ強制的にナビゲートしたい場合は、
force: true
オプションを検討してください。ただし、多くの場合はreplace: true
を使うことで、履歴を汚さずに現在のURLを「更新」する目的を達成できます。 - 遷移先のコンポーネントでのデータ取得との連携:
router.push
で遷移した後、遷移先のコンポーネントでは通常、$route.params
や$route.query
の値を利用してデータを取得します。コンポーネントのcreated
やmounted
ライフサイクルフック、またはwatch
やwatchEffect
を使って$route
オブジェクトの変化を監視し、必要に応じてデータを再取得するロジックを実装します。NuxtではasyncData
やfetch
フックがこの役割を担いますが、これらのフックはルートのパラメータやクエリの変更に自動的に反応しない場合があるため、設定 (watchQuery
) や$route
の監視を手動で行う必要があるか確認してください。
これらの注意点を理解し、ベストプラクティスに従うことで、router.push
をより安全かつ効果的に使用することができます。
まとめ
router.push
は、Vue.js および Nuxt.js アプリケーションにおけるプログラム的な画面遷移の根幹を担うメソッドです。宣言的な router-link
とは異なり、JavaScriptコードから動的にナビゲーションを制御できるため、ユーザーアクションやアプリケーションの状態変化に応じた柔軟な画面遷移を実現できます。
この記事では、router.push
の基本的な概念から始まり、ブラウザ履歴における push
と replace
の違い、そして最も重要であるロケーションオブジェクトによる詳細な指定方法とその各オプション (path
, name
, params
, query
, hash
, replace
, force
, state
) について、具体的な例を交えて解説しました。
また、Vue Router v3.1以降で router.push
が Promise を返すようになったことによる非同期処理 (async
/await
) との連携、ナビゲーションガードとの関係、そしてNuxt.js環境におけるアクセス方法やSSR時の注意点にも触れました。
これらの知識を身につけることで、ログイン後のリダイレクト、フォーム送信後の遷移、動的なパラメータに基づいた詳細ページの表示、クエリパラメータによる状態管理など、様々な要件に対応したリッチでインタラクティブなユーザー体験を構築できるようになります。
router.push
を使いこなすための鍵は、ナビゲーション先を正確に指定するためのロケーションオブジェクトの理解、特に name
と params
の適切な組み合わせ、そして query
や hash
を活用する方法です。さらに、非同期処理やナビゲーションガードとの連携、そしてSSR環境での注意点を押さえることで、より複雑なシナリオにも対応できるようになります。
この記事が、あなたがVue/Nuxtアプリケーションで router.push
を効果的に活用するための一助となれば幸いです。
関連リソース
- Vue Router 公式ドキュメント – プログラムによるナビゲーション: https://router.vuejs.org/ja/guide/essentials/navigation.html
- Nuxt ルーティング ドキュメント: https://nuxtjs.org/docs/directory-structure/pages (Nuxt 2)
- Nuxt 3 ルーティング ドキュメント: https://nuxt.com/docs/getting-started/routing