2019.10.28
Vueでカクテルデータベースをリファインする話#16【ナビゲーションガード】
これを読んでる人になんの需要もないけど僕のメモ帳として残してるプログラミング日記です。どうもこんにちは。
もうVueの話はしばらく書かないかなぁ〜〜なんて思ってたんですが、大事なことを1つ忘れてました。
ナビゲーションガードの話です。これがまだ未解決なんですよね・・・・・・
プログラミングやめたい・・・・・・
何の話かっていうと、例えばカクテルを検索するんですが、その時URLが遷移するじゃないですか。で、もっかいポップアップから検索して、送信されるパラメータが変わったとしてもpost送信なのでURLは変わらないわけです。
そうなると古いコンポーネントのデータが再利用される・・・・・・つまり
新しく取得してきた結果を用いて画面が再描写されないっていう問題が発生します。
具体的にはこういうエラーですね。これを解決して、リレンダリングしてもらえるようにあれこれしたいと思います。
で、めちゃくちゃ今頑張ってなんとかしようとしてるんですが、入ってくれることを期待してるウォッチャ類に処理が入らないので、どこか根本的なところを理解できていないのか・・・・・・?みたいな感じになってます。
ただ、なんとなくこれはわからない感じがしてきたので
別の方法でごまかすことを考えてみようと思います。そもそも想定されていない動作の可能性もあるしね。渡してるのがプロパティじゃなくてオブジェクト、っていうのもイレギュラーなケース感ありますし。実際のユースケースとコードを見るまでは理解できない気がします・・・・・・。
正解を見せてくれたらわかるんだけどなあ
1.Vuexに書き換える
状態が遷移されてこないのが問題なので、じゃあグローバルに持たせてしまえという発想ですね。個人的には常にグローバルに状態を無意味にもっておくことの前向きな理由が見いだせないですね・・・・・・。
あと、単語検索ならURLを変更できたんですけど、今回の場合はどうあがいても無理なんですが、結局顕在化する問題は変わらないよーーーーな???
2.状況に応じて分岐する
逃げの一手みたいなとこありますね。既にURLが遷移先のものであったら処理を変えて・・・・・・みたいな。
最初はこうするしかないかなぁ・・・・・・とか思って書き始めたんですけど
そもそも無理では・・・・・・???
で、いろいろ調べてみたんですけどやっぱり解決法がわからなかったので、この上記2つの合わせ技で対応することにしました。
プログラムは動けばいいんだよ!!!!!!(真理)
どういうことかというと、まず検索結果はVuexにてシングルトンで管理します。これはまた別にモジュールを定義すればそこまでソースコードは汚染されないかなって思います。
で、ページの更新ですが、このストアの変更を察知して、computedもしくはwatchで再描写させます。
で、ルーティング問題ですね。名前から検索する時と違って、パラメータの明示的な変更が使えないので、現在のURLを取得して比較して、パスが指定のものじゃなかったら、つまり適切な画面じゃなかったらジャンプしましょうね〜〜〜って感じでいいかなって思います。これで一応理論上は実装できるはずです・・・・・・。
まーーーじで苦し紛れみたいなロジックなんですけど仕方ありません・・・・・・。
とりあえず結論からいうと、ちゃんと動きました・・・・・・。
ソースコードは別に載せるほどでもないですが、イベント購読部分ぐらいは載せようかな。
mounted:function(){
this.$store.subscribe((mutation, state) => {
if (mutation.type === 'cocktailform/setResult') {
//結果が取得できたらこれが発火する。
//もし結果表示画面でない場合、結果表示画面に飛ばす。
if(this.$route.name !== 'SearchCocktailResult') {
this.$router.push({name: 'SearchCocktailResult'});//結果表示画面に飛ばす
}
this.$emit('closeForm');//親コンポーネントにダイアログを閉じさせる
}
})
},
このコードがすべてですね。mountedでこういうものを定義しておくと、ミューテーションがコミットされるたびにこれが呼ばれるようになります。
用があるのは
cocktailform/setResultミューテーションだけなので、そこだけを購読します。
パスの直接指定よりかはルートにつけた名前のほうが変更に対応できるので、名前で比較します。で、もし検索結果表示画面以外だったら画面遷移を行います。画面描写はコンポーネント内で勝手にやってくれるので、コンポーネントに任せましょう。このメソッドがやる仕事は遷移だけです。
もちろんすでにコンポーネントを開いている(今回の問題が発生するパターン)であれば何も遷移する必要がないので、そのまま閉じる、と。
で、ダイアログボックスを閉じなくてはいけないんですが、ダイアログボックス自体はこのフォームの親コンポーネントが管理してるので、そのままemitすればいいって感じですね。
<template>
<div>
<div>結果</div>
<Cocktail
:cocktails=this.Cocktail
></Cocktail>
</div>
</template>
<script>
import { mapState } from 'vuex'
import cocktail from "./children/Cocktail"
export default {
components: {
Cocktail: cocktail,
},
computed: {
...mapState("cocktailform",{
Cocktail:state=>state.result.Cocktail,
}),
},
}
</script>
ちなみに、検索結果表示画面のコンポーネントはこれでおわりです。Cocktailというコンポーネントは、名前から検索の時に使ったものをそのまま使いまわせばいいので、ただオブジェクトを渡せばいい感じに描写してくれます。
で、そのオブジェクトはcomputedにより常にストアを監視していることになるので、僕がやるべきなのはストアの中のオブジェクトを書き換えるだけで済むことになります。めちゃくちゃ簡単な作りになります。
いやーーー、動くときもちいいね、やっぱり。
とりあえず検索画面に関してはこれで終わりなので、ついに各論画面に入りたいと思います。
ただぶっちゃけそんなに変なことする予定はないので、このへんはサクっと終わらせて鬼門である管理画面&認証に進みたいところ。そう、結局未だに認証がよくわかってないんですよね・・・・・・。
Vuexで状態をもたせればなんとかなるのかなぁ・・・・・・まぁ最初に試みた時と違ってVueの知識はちゃんと持ってるわけだし、なんとかなると信じましょう^^