Vuexメモ
Vuexとは
コンポーネント間でデータのやり取りをすると、親子のネストが深いと
バケツリレーのようにデータの受け渡しが発生し作りが煩雑な作りになる。
Vuexはそれを防ぐために使われるモジュールのこと。
公式には状態管理パターン + ライブラリと呼ばれている。
ここでの状態管理とは、コンポーネントで使用されるデータのことを言っている。
ストアはデータの入れ物でコンポーネントがストアにアクセスすることで、
データのやり取りをすることができる。
ストアは一つのアプリケーションにつき一つのストアを使用したほうがいい
これはデータの整合性を保ち管理しやすくするようにするため。
Vuexの機能は下記で構成されている。
- Action
- Mutation
- State
- Getter
Action
コンポーネントからデータの取得や、データの更新の支持を受ける機能
この機能ではコンポーネント側へデータを渡す事はできない。
Mutation
Actionから受け取ったデータをStateへ格納したり、
既存のデータを更新したりする。
すべてのデータ変更はこのMutationを介してStateへ格納される。
つまり Vuex のストアの状態を変更できる唯一の存在
SQLのinsertとupdate的な
State
データの保持をしている機能。
ストア内のデータはすべてここに入る。
信頼できる唯一の情報源
一応コンポーネントはここからデータを直接取り出せる。
データを加工しない場合、ここに保存されたデータを直接参照したい場合はここから取り出す。
DB的な
Getter
GetterはStateの情報を加工し、コンポーネントへ渡したい場合に使用する。
例)StateのUserListから特定のUserを取り出したい場合など
取り出し専用のSQL文的な
使い方
※ここに書かれているのはVueの新規プロジェクトの作成から立ち上げまで
で作成した後のファイル構成を前提にして書いています。
src/store/index.js
を編集する。初期状態は下記の通り。
Getterの記載がないが、必要なときはgetters:{},
のようにして使用する。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { }, mutations: { }, actions: { }, modules: { } })
値の受け渡しをしたい変数をstate
に記載
state: { drawer:false },
actions
には下記のように記載
actions: { toggleSideMenu({ commit }){ commit('toggleSideMenu') } },
これは何をやっているかというとActionで定義されたメソッドの引数では、
自動的にcontext
オブジェクトが入ってくる。引数の{{commit}}
は、
context.commit
メソッドだけを受け取るようにした書き方。
受け取れるメソッドはここ
ちなみに引数がある場合は、
toggleSideMenu({ commit }, input1){
のように書く。
commitメソッドはmutation
のメソッドを呼び出すために使用されるデータのこと、
ここではtoggleSideMenu
という文字列を引数として渡しているので、
この文字列に対応したdrawer
変数を変更する処理をmutations
に記載する。
mutations: { toggleSideMenu(state){ state.drawer = !state.drawer } },
これでcommit
でtoggleSideMenu
が呼び出された場合
mutations
のtoggleSideMenu
が呼び出される。
mutations
のメソッドの引数には自動的にstate
オブジェクトが入ってくるので、
state
で宣言したdrawer
の値を変更することができる。
ちなみに引数がある場合は、
toggleSideMenu(state, input1){
のように書く。
コンポーネントからストアを呼び出す方法
下記はsrc/components/SideNav.vue
に記載する
ストアへのアクセスの仕方は$store
でアクセスできて、
state
を使用する場合は$store.state
と記載する。
そして今回はdrawer
にアクセスしたいので、$store.state.drawer
のように記載する
これで開閉状態をストア依存でできるようになった。
完成形は下記
<template> <v-layout wrap style="height: 200px;"> <v-navigation-drawer v-model="$store.state.drawer" absolute temporary> <v-list class="pa-1"> <v-list-tile avatar> <v-list-tile-avatar> <img src="https://avatars2.githubusercontent.com/u/1363954?s=460&v=4"> </v-list-tile-avatar> <v-list-tile-content> <v-list-tile-title>Kazuya Kojima</v-list-tile-title> </v-list-tile-content> </v-list-tile> </v-list> <v-list class="pt-0" dense> <v-divider></v-divider> <v-list-tile v-for="item in items" :key="item.title" :to="item.link"> <v-list-tile-action> <v-icon>{{ item.icon }}</v-icon> </v-list-tile-action> <v-list-tile-content> <v-list-tile-title>{{ item.title }}</v-list-tile-title> </v-list-tile-content> </v-list-tile> </v-list> </v-navigation-drawer> </v-layout> </template> <script> export default { data () { return { items: [ { title: '連絡先一覧', icon: 'list' } ] } } } </script>
次はヘッダーのアイコンからdrower
の値を変更できるようにする。
対象のファイルはsrc/App.vue
弄るのはここ<v-toolbar-side-icon></v-toolbar-side-icon>
ここをクリックされた時にAction
が呼び出され、drower
の値が変更されるように処理を追加する。
(メニューバーの開閉ができるようにする)
Action
の呼び出し方には二種類ある。
Actionの呼び出し方-dispatch
data
部分を下記のように変更する。
export default { name: 'App', components:{ SideNav }, data () { return { // } }, methods:{ openSideMenu(){ this.$store.dispatch('toggleSideMenu') } } }
methods
でstore
を呼び出すときはthis.$store
で呼び出すことができる
。
そしてstore
はdispatch
というメソッドを持っていて、このメソッド経由でActionを呼び出すことができる。
今回はsrc/store/index.js
で記載したtoggleSideMenu
のアクションを呼び出せる。
後はこのopenSideMenu
メソッドを@click
で呼び出せば使える
<v-toolbar-side-icon @click.stop="openSideMenu"></v-toolbar-side-icon>
App.vueの最終形
<template> <v-app> <v-toolbar app> <v-toolbar-side-icon @click.stop="openSideMenu"></v-toolbar-side-icon> <v-toolbar-title class="headline text-uppercase"> <span>マイアドレス帳</span> </v-toolbar-title> <v-spacer></v-spacer> </v-toolbar> <SideNav/>> <v-content> </v-content> </v-app> </template> <script> import SideNav from './components/SideNav' export default { name: 'App', components:{ SideNav }, data () { return { // } }, methods:{ openSideMenu(){ this.$store.dispatch('toggleSideMenu') } } } </script>
Actionの呼び出し方-mapActions
mapActions
を使うとdispatch
を使うよりも簡単に記述することができる
先程dispatch
でも書き換えたsrc/App.vue
をmapActions
用に変更する
mapActions
メソッドを使うにはimport { mapActions } from 'vuex'
でインポートする必要がある。
これにより、コンポーネントのメソッドにActionメソッドを組み込む事ができる。
ちなみに普段のインポートとは違い{mapActions}
のように記載しているのは、ES6の分割代入を利用している
分割代入をについてはここ
その後methods
を下記のように変更する。
methods:{ ...mapActions(['toggleSideMenu']) }
mapActionsメソッドの引数には配列を渡すして使用したいActionメソッド名を記載
複数使用したいActionがある場合は配列に追加するとメソッドに組み込める。
mapActionsの前の...
は分割代入の構文
これにより、toggleSideMenu
は不要になりtoggleSideMenu
だけですむので、
こちらを使うほうが読みやすくなる。
App.vueの完成形は下記
<template> <v-app> <v-toolbar app> <v-toolbar-side-icon @click="toggleSideMenu"></v-toolbar-side-icon> <v-toolbar-title class="headline text-uppercase"> <span>マイアドレス帳</span> </v-toolbar-title> <v-spacer></v-spacer> </v-toolbar> <SideNav/>> <v-content> </v-content> </v-app> </template> <script> import SideNav from './components/SideNav' import { mapActions } from 'vuex' export default { name: 'App', components:{ SideNav }, data () { return { // } }, methods:{ ...mapActions(['toggleSideMenu']) } } </script>
Getterの呼び出し方-mapGetters
使い方はmapActions
と大体同じだけど、呼び出すときはmethods
ではなく
computed
で定義する
まずvue/state/index.js
を下記のように書く
getters:{ userName: state => state.login_user ? state.login_user.displayName : '', photoURL: state => state.login_user ? state.login_user.photoURL:'' },
コンポーネント側では下記のようにimportし配列形式で定義
あとはテンプレート側から呼び出したりできる。
import { mapGetters } from 'vuex' ~~~~~~~~~~~~~~~ computed:{ ...mapGetters(['userName','photoURL']) }