2019.9.10
Vueでカクテルデータベースをリファインする話#3【store】
昨日API通信が上手く行ったので、いよいよVueの本領発揮というか、受け取ったJSONデータをそのままビューに流し込んで表示させる、っていうところをやりたいと思います。
で、まず問題となってくるのは受け取ったデータをどこに格納するか、ですね。件数表示の時点でSQLが発行できててデータも取得するほうがエコなので、もう一回APIを叩くのではなく、保存してあるデータをそのままページに表示させたいところです。
ただ、普通にやってるとそのオブジェクトにアクセスができないので
ストアをどっかに用意する必要がありそうです。
まぁそういうときのためにVuexがあるんですが、小規模サービスには向かないということでもうちょっと原始的な方法を取り入れたいなと思ったんですが、何やってもうまく行かなかったのでいきなりVuex導入することにしました(!?)
まずストアの導入ですね。クソほどハマりましたが一応導入できました。
半日かかった・・・・・・これだからプログラミングは嫌いなんだ・・・・・・
//関係ない記述は消しています
import Vuex from 'vuex'
Vue.use(Vuex)
const store=new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
});
const app = new Vue({
store,
router,
el: '#app'
})
とりあえず、一番簡単な形。app.jsに直接ぶちこんでる形ですね。
これを深い階層のコンポーネントから呼び出せれば、シングルトンが生成され呼び出すことに成功している、という認識で良さそうです。
で、いま実装している検索バーは親コンポーネントの孫かその子ぐらいの比較的深い階層のコンポーネントなので、ここから直に普通に呼び出せれば良いことになります。
methods:{
getResult:function(data){
var vm=this;
this.$store.commit('increment')
console.log(this.$store.state.count)
}
},
省きまくりましたけど、これでアクセスできました。
肝なのは
this.$storeの部分ですね。
ドキュメントに書けよウンコはげナスビクソ野郎...
参考にしたコードは
これなんですけど、なんでこうなるのかって話ですね。
何読めばわかるんだよ
一応、頭にドルマークがついている変数は、システム定義変数ということになってるみたいです。
じゃあなんで公式ドキュメントにはついてねンだよ!?!?死ね!!!!!
で、軽く調べたんですが
よくわからなかったので、もうそういうもんだと考えることにしておきます。とりあえずこれで動くんだから良し。this.$storeでアクセスできる、っていうのだけ認識していれば使えそうなので。
で、このままの書き方だと全く実用的ではないので
モジュール化を試してファイルを分割できるようにしておきます。
少なくともカクテルDBではあんまり有用に使えないと思うんですけど、ログイン状態管理関係と少なくとも2つのモジュールには分かれると思うんで。
うまくいったサンプルとしては
ここと
ここがわかりやすかったかな。
あとモジュール分割および名前空間に関しては
この記事を参照してやっとわかりました。
っていうか公式ドキュメントがよくわかんねえんだよハゲナスビ
まずは単純なモジュール分割のご紹介です。っていうかメモ書き。
import store from './store'
const app = new Vue({
store,
router,
el: '#app'
})
まず大元となるjsファイルに、外部ファイルのモジュールを読み込んで組み込む、っていうのをやります。
今まではこのapp.jsにconstでstoreを定義してましたけど、それを外部ファイルに移した形になりますね。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const moduleA = {
namespaced: true,
state: {},
getters: {},
mutations: {},
actions: {}
}
const moduleB = {
namespaced: true,
state: {
countx: 135
},
mutations: {
},
actions: {
}
}
export default new Vuex.Store({
modules: {
aaa: moduleA,
bbb: moduleB
}
})
まずはモジュール分割の部分だけ試すことにします。1行目のvueインポートは必須らしい。app.jsで読み込んでても関係ないらしい。PHPとはimportの仕様が違うんかな。それともモジュールとしてimportしてるから、それぞれのファイルは独立していると考えた方が良いのかな。
で、Vue.use(Vuex)というおまじないでVuexを使えるようにします。
モジュールに関してはmoduleAとmoduleBを用意します。namespaced:trueの部分がキモのようですね。これで名前空間が使えるようになるオプションです。これがないと、名前が被ったミューテーション等を呼び出した時に全部一斉に呼び出されてしまうらしい。
で、この2つのモジュールを、aaa,bbbという名前で名前空間に登録しているイメージです。
で、実際任意のファイルから呼び出す時にどうしたら、って話ですね。
<template>
<div>
<div>{{this.count3}}</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: "fromName",
~略~
computed: {
...mapState("aaa",{}),
...mapState("bbb",{
count3: state => state.countx,
})
},
}
Vueファイルからはこんなふうに読み込みます。mapStateというモジュールかなんかを読み込むとちょっとラクができます。
これはcomputedのとこで「...」っていうスプレッド演算子を用いて定義します。特定の場合はなくてもいいんですけど、原理的なものを理解したほうがいいと思うので素直にスプレッドにします。
モジュールAに関しては空なんで無視して、モジュールBのcountを読み込むことができれば、とりあえず構造と呼び出し方が合ってることが確認できるのでそこを攻めます。
ということでこのVueファイルはモジュールBのcountを表示させるだけのファイルです。
名前をあえてcount3というのに変えてますが、computed部分で、名前空間bbbのstate.countxをcount3と定義する、という書き方で定義しています。
これにより、this.count3という名前で解決することができてそのまま読み出せるようになるわけですね。これを普通に呼ぼうとするとどうなるんだろう。
this.$store.state.bbb.countxとかになるらしい。bbbよりも先にstateが来るのがミソかな。stateで一元管理されてて、その中にモジュールがあるっていうイメージなんだろうか。
とりあえず呼び出すことはできるようになったので、このmoduleAとmoduleBを別のファイルに分けたいと思います。
少なくともこのストアはシングルトンとして保持しておくべき情報、つまり認証モジュールと検索モジュール
(検索が重い操作なので可能ならばキャッシュしておきたい)の2つはカクテルDBにおいて必要になってくると思いますしね。
その方法は
このページを参照しながら考える。
import search from './Modules/search'
export default new Vuex.Store({
modules: {
search: search,
}
})
export default {
namespaced: true,
state: {
data: {
message: 'モジュールCだよ'
}
},
getters: {
}
}
(略)
computed: {
...mapState("search",{
msg: state => state.data.message,
}),
},
まぁ普通にできましたね。
次は、このストアにメソッドを集約させなくてはいけないので、この前作った検索周りのメソッドをこのストアに移動させて管理させやすくします。