LoginSignup
5
1

More than 3 years have passed since last update.

[vue-router] BeforeRouteLeaveが2度発火する

Last updated at Posted at 2019-07-28

TL;DR

  • Vue-RouterBeforeRouteLeave等ナビゲーションガードが二回発火する場合がある。
  • 遷移先のコンポーネントに何らかのリダイレクトがあるときに発生する。
  • toを調べることで回避可能。

同じ問題を扱ったissue
=> https://github.com/vuejs/vue-router/issues/2102

本件は仕様として扱われるようなので、今後しばらく対応される見込みはなさそう。

再現環境

  • Chrome バージョン: 75.0.3770.142
  • Nuxt 2.6
  • vue-router 3.0

リポジトリと検証動画

https://github.com/IKKO-Ohta/invoke_brl_twice
output.gif

トップページ - ページ1 - ページ2という構成で、

  • ページ2のバックボタンを押すと、window.confirm()を表示する。「OK」を押すとページ1に遷移する。
  • ページ1では、ページ2からの遷移をキャッチするとトップページに飛ばす

想定としては、例えば商品販売サイトにおいて、ページ2が注文完了画面で、ページ1が決済確認ページ、くらいのとき。
しかしこのとき、ページ2のBeforeRouteLeave が2度発火する。window.confirm()のOKを1度押しても再度ダイアログが表示される。

どうして起こるか?

予想

ex.png

2 => 1, 1 => top のような遷移をしそうな気がする。

実際

rec.png
実際のページ2のbeforeRouteLeaveはこのように挙動する。

beforeRouteLeaveが 2=>1 と 2 => top の2回分呼ばれる。引数のfrom.nameto.nameの中身を調べると確かにそうなっている。1=>top へのリダイレクトがこの2回目の遷移を誘発させる。このとき1=>topの遷移でもない! あくまで from="2", to="top"のbeforeRouteLeaveが走る!

解決策

ページ2beforeRouteLeavetoを検査し、一回目の遷移についてガードしないようにすれば良い。

before

  beforeRouteLeave(to, from, next) {
    window.confirm("このページを離れますか?") ? next() : next(false);
  }

after

  beforeRouteLeave(to, from, next) {
    if (to.name === "first") {
      next();
      return;
    }

    window.confirm("このページを離れますか?") ? next() : next(false);
  }

なお、afterは可読性の低いコードなので(一見「戻る」のときにはガードしない、というコードに見える)公式issueなどを引用して適宜コメントに追記することを推奨する。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1