11
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue Routerでquery書き換えができなかった(凡ミス)

Posted at

試行錯誤の段階を記載しているので急いでいる方は下へ。

問題

Vue Routerを使用してqueryを書き換えようとすると次のように怒られた。

Uncaught (in promise)
NavigationDuplicated {
    _name: "NavigationDuplicated",
    name: "NavigationDuplicated",
    message: "Navigating to current location ("/blog?page=3") is not allowed",
    stack: "Error↵    at new NavigationDuplicated (webpack-int…node_modules/vue/dist/vue.runtime.esm.js:1853:26)"
}

Error
    at new NavigationDuplicated (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2013:14)
    at HTML5History.confirmTransition (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2129:18)
    at HTML5History.transitionTo (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2073:8)
    at HTML5History.replace (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2416:10)
    at eval (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2829:22)
    at new Promise (<anonymous>)
    at VueRouter.replace (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2828:12)
    at Proxy.set (webpack-internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/blog/article_list.vue?vue&type=script&lang=ts&:190:20)
    at callback (eval at ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"900baf1e-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/blog/article_list.vue?vue&type=template&id=ee03622c&scoped=true& (http://localhost:8080/js/article_list.js:23:1), <anonymous>:115:29)
    at invokeWithErrorHandling (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:1853:26)"
 at invokeWithErrorHandling (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:1853:26)"

どうやら同じrouteに遷移しようとしていると思われているらしい。
実際はちゃんと別routeへ動こうとしているので、何かがおかしい。

ソース

問題のソースはこれ。(抜粋)(変更)

let query = this.$route.query;
query["page"] = page.toString();
this.$router.push({ query });

GitHubを調査

https://github.com/vuejs/vue-router/issues/2872
それっぽいissueをみつけた。
解決方法としては、Exceptionを握りつぶすというもの。
(わざと同じルートへ動こうとしたときのissueだろうか?)

ただ、同じルートへ遷移しようとすると無視するという仕様のもとでエラーを無視したところで得られるものは何もなく…

ソースを観察

stacktraceをもとに元凶であると思われるファイルへ。(node_modules/vue-router/dist/vue-router.esm.js:2129)

vue-router.esm.js
  if (
    isSameRoute(route, current) &&
    // in the case the route map has been dynamically appended to
    route.matched.length === current.matched.length
  ) {
    this.ensureURL();
    return abort(new NavigationDuplicated(route))
  }

isSameRouteの定義を見にいく。

vue-router.esm.js
function isSameRoute (a, b) {
  if (b === START) {
    return a === b
  } else if (!b) {
    return false
  } else if (a.path && b.path) {
    return (
      a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
      a.hash === b.hash &&
      isObjectEqual(a.query, b.query)
    )
  } else if (a.name && b.name) {
    return (
      a.name === b.name &&
      a.hash === b.hash &&
      isObjectEqual(a.query, b.query) &&
      isObjectEqual(a.params, b.params)
    )
  } else {
    return false
  }
}

しっかりqueryが異なることを確認しているように見える。

実験

先のisSameRouteの冒頭でa,bの中身をconsole.logで確認する。

a: {
  name: "article_list",
  meta: {},
  path: "/blog",
  hash: "",
  query: {page: "3"},
  params: {},
  fullPath: "/blog?page=3",
  matched: [{}],
  __proto__: Object
}

b: {
  name: "article_list",
  meta: {},
  path: "/blog",
  hash: "",
  query: {page: "3"},
  params: {},
  fullPath: "/blog?page=2",
  matched: [{}],
  __proto__: Object
}

queryとfullPathで齟齬が出ていることがわかった。
原因を考えてみると、問題のソースの1行目、オブジェクトを参照でコピーしていることに気づいた。

let query = this.$route.query;

これを次のように変更することで修正できた。

let query = Object.assign({}, this.$route.query);

まとめ

JSのオブジェクトの代入には細心の注意を。参照渡しで痛い目にあいます。

(問題の核心はVue-routerとは少し離れますが、関係はしていたのでタグ付けしました)

11
8
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
11
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?