参考にさせて頂いたページ
はじめに
APIにリクエストする非同期な処理を想定して、actionsからcommitしています。 実際にAPIとか作ったらもう少し違う実装が適切かもしれないです。
ES2015が使えない環境下でのことを考慮するなど個人的事情からlodashを使用していたり、とはいえ全体的にはES2015で書いていますがそこはそっとスルーでお願いします。
今回のバージョン
- Vue.js v2.1.10
- vuex v2.3.0
サンプルソースコード
例として以下の通りです。
<!DOCTYPE html> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta charset="utf-8"> <title></title> <meta name="description" content=""> <meta name="author" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="css/style.css"> <link rel="shortcut icon" href=""> </head> <body> <style> .is-done { color: #999999; text-decoration: line-through; } </style> <h1>タスク管理アプリケーション</h1> <div id="app"> </div> <script src="js/lodash.js"></script> <script src="js/vue.js"></script> <script src="js/vuex.js"></script> <script> /** * store */ const store = new Vuex.Store({ strict: true, state: { latestItemId: null, items: [] }, getters: { }, actions: { addItem({commit, rootState}, content) { // 実際はここでAPIにリクエストしてDBのレコード追加が成功したらcommit const newItemId = rootState.latestItemId + 1; commit('addItem', {id: newItemId, content: content, isDone: false}); }, toggleItem({commit, rootState}, id) { // 実際はここでAPIにリクエストしてDBの当該レコードの更新が成功したらcommit const index = _.findIndex(rootState.items, function(o) { return o.id == id; }); commit('toggleItem', index); }, deleteItem({commit}, id) { // 実際はここでAPIにリクエストしてDBの当該レコードの削除が成功したらcommit commit('deleteItem', id); }, getItems({commit}) { // 実際はここでAPIにリクエストしてDBからタスクリストを取得します const items = [ {id: 0, content: '起きる', isDone: false}, {id: 1, content: '朝食を食う', isDone: false}, {id: 2, content: '昼食を食う', isDone: true}, {id: 4, content: '夕食を食う', isDone: true}, {id: 5, content: '風呂に入る', isDone: false}, {id: 10, content: '寝る', isDone: false}, ]; const latestItemId = items[items.length - 1].id; commit('getItems', {latestItemId: latestItemId, items: items}); } }, mutations: { addItem(state, newItem) { state.latestItemId = newItem.id; state.items.push(newItem); }, toggleItem(state, index) { state.items[index].isDone = !state.items[index].isDone; }, deleteItem(state, id) { state.items = _.filter(state.items, function(item) { return item.id !== id; }); }, getItems(state, newState) { _.assign(state, newState); } } }); /** * addItem * タスク新規追加フィールドのコンポーネント */ const addItem = { data() { return { content: '', } }, template: ` <section> <h2>タスクを新しく追加</h2> <div> <input type="text" v-model="content"> <input type="submit" value="追加" @click="addItem"> </div> </section> `, methods: { addItem() { if (!this.content) return; this.$store.dispatch('addItem', this.content); this.content = ''; } } }; /** * item * タスク一つ分のliタグのコンポーネント */ const item = { props: ['item'], template: ` <li> <span :class="{'is-done': isDone}">id {{item.id}} : {{item.content}}</span> <button @click="toggleItem" v-text="buttonLabel"></button> <button @click="deleteItem">削除する</button> </li> `, computed: { id() { return this.item.id; }, isDone() { return this.item.isDone; }, buttonLabel() { return this.item.isDone ? '未完了に戻す' : '完了にする'; }, }, methods: { toggleItem() { this.$store.dispatch('toggleItem', this.id); }, deleteItem() { if (!confirm("削除しますか?")) return; this.$store.dispatch('deleteItem', this.id); }, } }; /** * itemList * タスク一覧のulタグのコンポーネント */ const itemList = { components: {item}, template: ` <section> <h2>登録されているタスク</h2> <ul> <item v-for="item in items" v-bind:item="item"></item> </ul> </section> `, computed: { items() { return this.$store.state.items; } }, created() { this.$store.dispatch('getItems'); } }; /** * app * rootのコンポーネント */ const app = new Vue({ el: '#app', store, components: { addItem, itemList, }, template: ` <div class="app"> <add-item /> <item-list /> </div> ` }); </script> </body> </html>
Vuexとは
Storeを提供し、以下のようなルールに則った開発をすることでコードの見通しがよくなります。
- Storeが持っているstateはmutationsによってのみ更新される
- mutaionsは同期的でなくてはならず、非同期な処理はactionsが担う
正確な情報は公式ドキュメントを参照してください。
個人的まとめ
あくまでも個人的なもので、ES2015などを使用しない環境下のせいもあると思いますが、参考になればと思います。
- VuexはStoreを提供するもので、コンポーネントは普通にVue.js単体で使っているときと同じ要領で書く
- rootコンポーネントにstoreオプションを設定すると、子コンポーネントで
this.$store
が参照できるようになる - コンポーネント内でstoreを参照するときは
this.$store
を使う - Storeは
strict: true,
を設定した方がいい - Storeが持っているstateはmutationsによってのみ更新される
- mutaionsは同期的でなくてはならず、非同期な処理はactionsが担う
- mutationsが持っているメソッドは第一引数に
state
を受け取る - actionsが持っているメソッドは第一引数に
context
または分割で{state, rootState, commit, dispatch, getters}
を受け取る - mutaionを呼ぶときはcommitで、actionを呼ぶときはdispatch
- getters, modules, plugins というキーもあるけど今回は使っておらず、いずれも大きい規模になるほど有用そう
- actionのdispatchとpromiseについては「アクション · GitBook」