普段、非同期でデータを取ってきてデータを表示する時は、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
を使う
以下のような感じでルーター更新時のライフサイクルを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
とはならないので注意。