Vue TypeScript マウント済みコンポーネント再利用時に非同期処理を行う。及びVuexのwatchについて

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

普段、非同期でデータを取ってきてデータを表示する時は、createdライフサイクルで非同期でこと足りるんだけど、$router.pushで同じコンポーネントに遷移しようとした場合、mount済みコンポーネントを再利用しようとして、created, mountedなんかが呼び出されずに画面が更新されない。というケース。

自分の場合、非同期処理で利用するパラメータはVuexで保持していたので、Vuexのstateを@Watchすれば何とかなるかなーと試してみたもののWatchに渡すpathがstringじゃないとダメだと叱られ、やり方が悪いのかうまくhookできない。

非同期じゃなければ、computed内でVuexのパラメータ使うだけで済むんだけどなあ。中々解決方法が見出せない。

次に試したのは$route.pushでpropsで渡しちゃえとこちらも試してみたもののpush時にpropsに対して、オブジェクトを渡す方法がうまく動作しない。いや、多分、オブジェクトの定義そのものをrouter/index.tsとかに記述すると動くような気はするが...(^_^;)

解決した方法

beforeRouteUpdateを使う

ナビゲーションガード | Vue Router

以下のような感じでルーター更新時のライフサイクルをhookできる。

Component.registerHooks(["beforeRouteUpdate"]);がないとダメなので忘れずに定義しよう。next()でpush時のpathに「URL」を更新する。これしとかないと、URLが遷移前のままなので注意。

import { Component, Vue } from "vue-property-decorator";
import VueRouter from "vue-router";

Component.registerHooks(["beforeRouteUpdate"]);

export default class MyComponent extends Vue {
  private data: myObject[] = [];

  private async beforeRouteUpdate(to: VueRouter, from: VueRouter, next: any) {
    next();
    const data = myVuexState.getData;
    const result = await 非同期処理(data);
    this.data = result.data;
  }
}


これ使ったほうが早かったのかなあ...

GitHub - foxbenjaminfox/vue-async-computed: Async computed properties for Vue.js

追記 TypeScriptでVuexのstateをWatchする

Watch単体でのやり方が分からなかったので、算術プロパティと組み合わせて動作させるとうまく動いた。

export default class MyComponent extends Vue {
  private data: myObject[] = [];
  private watchdata: myVuexState | null = null;

  //vuexのstateをwatchする
  private get setwatchdata() {
    this.watchdata = myVuexState.getData;
    return null;
  }

  //算術プロパティでセットされるプロパティをwatchする
  @Watch("watchdata")
  private async watchevent() {
    const result = await 非同期処理(this.watchdata);
    this.data = result.data;
  }
}

算術プロパティが想定されている使い方じゃないだろうから、Vuex自体のwatch方法が知りたい笑

追記: 上記では、何故かdeveloper tool起動時のみwatchできる笑

vuexのstate, getterを監視するには、コンポーネントのライフサイクルイベントで、以下のように記述する。

private watchdata = "";

private async created() {
    this.$store.watch(
      (state, getters) => getters["namespace/methodName"],
      (newValue, oldValue) => {
        this.watchdata = newValue;
      }
    );
}

getters["namespace/methodName"]についてはstoreのnamespaceとgetterのmethodnameをブラケット / 区切りで指定する。getters.namespace.methodNameとはならないので注意。