1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vue Routerのコンポーネントリロードを実現する

Posted at

はじめに

VueでSPAを作成する際によく使われるVue Routerにて、現在のコンポーネントをリロードさせる方法について考えてみました。
クエリやパラメータなどを変更して再読み込みしたい場合など、リロードしたいケースが出てくる時はあると思います。
ただ、同じルートだとrouter.pushを使用してもコンポーネントのリロードは行われないので、方法を考える必要がありますね。

調べてみると、こちらの記事やその他の記事でrouter.go({ path: router.currentRoute.path, force: true })でできるとありましたが、どこかで仕様が変わったのか現在(ver4.4.0)だと動作しません。
恐らくVue3になり、それに対応するver4.xから色々と変わったのだろうと思いますが…
考えて実装してみました。

方法

ということで早速ですが、実装したのが以下のコードです。

app-router.vue
<script setup>
import { RouterView } from 'vue-router';
import useRouterComponentStore from './router-component-store.js';

const routerComponentStore = useRouterComponentStore();
</script>

<template>
  <RouterView :key="routerComponentStore.key"/>
</template>
router-component-store.js
import { defineStore } from 'pinia';

const useRouterComponentStore = defineStore('routerComponent', () => {
  const key = ref(1);

  /** コンポーネントのリロード */
  function reload () {
    key.value *= -1;
  }

  return { key, reload };
});

export default useRouterComponentStore;
index.js
import { createApp } from 'vue';
import { createRouter, createWebHashHistory } from 'vue-router';
import AppRouter from './app-router.vue';

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    {
      path: '/',
      name: 'home',
      component: () => { return import('./views/home.vue'); }
    },
    {
      path: '/detail',
      name: 'detail',
      component: () => { return import('./views/detail.vue'); }
    },
    // その他ルーティング設定
  ]
});

createApp(AppRouter)
.use(router)
.mount('#app');

ひとまず解説をすると、<RouterView :key="routerComponentStore.key"/>が肝になります。
Vueの特別な属性としてkeyが存在しており、これの値を変動させることでそのコンポーネントを再読み込みさせることができます。
つまりRouterViewkeyを設定し、リロードしたい時にそのkeyの値を変更すれば現在のルートのコンポーネントをリロードできる訳ですね。

後はkeyの値を変更させる方法になります。
v-model:keyで設定して各router内のコンポーネント側で個々にemitする方法とかもありますが、今回はpiniaを使用しています。
piniaでrouterComponentストアを定義してそこにkeyの値を設定し、keyを更新するreload関数を定義します。
関数内の処理ではとにかくkeyの値が変わればいいので、何回呼び出しても無限に値が変わるように1と-1を交互に繰り返すロジックにしてみました。

後は個々のコンポーネントでrouterComponentストアを呼び出し、reload関数を実行すればリロードできます。こんな感じ。

detail.vue
<script setup>
import useRouterComponentStore from './router-component-store.js';

const routerComponentStore = useRouterComponentStore();
</script>

<template>
  <div>詳細</div>
  <button type="button" @click="routerComponentStore.reload()">画面更新!</button>
</template>

これでリロードをお好みのタイミングでできますね!

注意点

今更ですが、この方法は再マウントが走るので処理としては重い形になります。(よっぽどのことが無い限りは気にするほどではありませんが)
onBeforeRouteUpdateを使用する形で十分なのか?など、本当に必要かを考えたほうがいいですね。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?