Vue School の無料コース「Vuex for Everyone」を受講した.Vue.js 初心者でも受講できるレベルになっているし,今まで Vue.js を書いたことはあるけど,Vuex はまだ使ったことがないという人にもオススメできる.進め方にもよるけど,写経するとしても2,3時間あれば終わる.
Vuex for Everyone
今回受講した「Vuex for Everyone」の題材は「shopping-cart」で,ステップバイステップに実装を進めていく.動作確認をしながら,機能を追加したり,リファクタリングをしたりする.
vueschool.io
動画を見るとわかるけど,とにかく実装スピードが早いので,写経する場合は何度も戻して見直す必要がある.ただ困ったときは Vue School の GitHub にセッションごとにコミットされているので,それを活用すればオッケー.
github.com
セッション一覧
- Introduction
- Meet Vuex ⏲ 2:46
- Create a new project with vue-cli ⏲ 3:45
- Install and use Vuex ⏲ 1:57
- Vuex Options
- Vuex Mutations ⏲ 3:22
- Vuex Getters ⏲ 1:57
- Vuex Actions ⏲ 4:25
- Store Access from all Components ⏲ 0:53
- Shopping Cart Features
- Add products to the cart ⏲ 5:08
- Vuex Mutation History and Vue Devtools ⏲ 2:46
- Cart items and total ⏲ 4:32
- Checkout ⏲ 3:49
- Advanced Vuex Options
- Dynamic Vuex Getters ⏲ 2:31
- Vuex Map Helpers ⏲ 8:04
- Split Vuex Store in Multiple Files ⏲ 1:11
- Vuex Modules ⏲ 7:23
- Namespaced Vuex Modules ⏲ 6:27
(受講画面例)
Meet Vuex
- Vuex とは何か?
- なぜ Vuex が必要なのか?
Create a new project with vue-cli
Vue School のボイラープレートから「shopping-cart」プロジェクトを作成する.
$ npm install -g vue-cli
$ npm install -g yarn
$ vue init vueschool/webpack-template shopping-cart
? Project name shopping-cart
? Project description A Vue.js project
? Author kakakakakku <y.yoshida22@gmail.com>
? Vue build runtime
? Install vue-router? No
? Use ESLint to lint your code? No
? Setup unit tests with Karma + Mocha? No
? Setup e2e tests with Nightwatch? No
vue-cli · Generated "shopping-cart".
To get started:
cd shopping-cart
npm install
npm run dev
Documentation can be found at https://vuejs-templates.github.io/webpack
$ cd shopping-cart
$ yarn
$ yarn dev
次に Vuex の GitHub にあるサンプルを参考に,ProductList コンポーネントを実装する.API 部分はモックになっている.
const _products = [
{"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2},
{"id": 2, "title": "H&M T-Shirt White", "price": 10.99, "inventory": 10},
{"id": 3, "title": "Charli XCX - Sucker CD", "price": 19.99, "inventory": 5}
]
この時点で,3商品を表示することができる.
(実装画面)
Install and use Vuex
ここで Vuex をインストールする.
$ yarn add vuex
そして,新しく store/index.js
を作成する.ここで,さっそく Vuex で重要なコンセプトが出てくる.
- state
- getters
- actions
- mutations
Vuex Mutations
ここでは,実際に mutations を実装する.ハンドラ関数の第一引数として state
を指定し,追加でペイロードとして products
を指定している.
mutations: {
setProducts (state, products) {
state.products = products
}
}
Vuex Getters
getters の実装はシンプルで,ストアからフィルタして取得できる.実際にモックの1商品の在庫を0にして,動作確認をした.
getters: {
availableProducts (state, getters) {
return state.products.filter(product => product.inventory > 0)
}
}
(実装画面)
Vuex Actions
この時点だと,まだコンポーネントから直接 Ajax で API を呼び出しているので,ベストプラクティスではなく,actions を使って解決するとのことだった.最初は,そのまま mutations をコミットすれば良いのではないかと思っていたけど,mutations は同期,actions は非同期なので,ここでは actions を使って,mutations をコミットする必要性を学べた.そして,API を呼び出しているときのローディング画像もここで実装した.
actions: {
fetchProducts ({commit}) {
return new Promise((resolve, reject) => {
shop.getProducts(products => {
commit('setProducts', products)
resolve()
})
})
}
},
actions を呼び出すときは .dispatch
を使う.そして actions の中で Promise を実装しているので,ここでは .then
で受けて,ローディング画像を消している.
created () {
this.loading = true
store.dispatch('fetchProducts')
.then(() => this.loading = false)
}
(実装画面)
Store Access from all Components
全てのコンポーネントで store を import しなくても良いように,ルートコンポーネントに注入し,各コンポーネントでは this.$store
で参照できるようにした.
new Vue({
el: '#app',
store,
render: h => h(App)
})
Add products to the cart
次に商品をカートに入れられるようにストアにカートを実装した.ここまでの理解もあったので actions と mutations の実装も問題なかった.
(実装画面)
Vuex Mutation History and Vue Devtools
Chrome 拡張を使って Vuex の状態を確認した.状態を Time Travel して戻すことができるのは,デバッグするときに便利そうだった.
(実装画面)
Cart items and total
Vuex の GitHub から Filters 用の currency.js
をコピーして,カートの実装を追加した.これで,カートの中に何が何個入っていて,総額も確認できるようになった.
(実装画面)
Checkout
次は,購入できるようにチェックアウトボタンを実装した.実際にチェックアウトはできないので,ボイラープレートに入っている実装で,ランダムで成功したり,失敗したりするようになっている.
buyProducts (products, cb, errorCb) {
setTimeout(() => {
(Math.random() > 0.5 || navigator.userAgent.indexOf('PhantomJS') > -1)
? cb()
: errorCb()
}, 100)
}
actions から,成功時の mutations と 失敗時の mutations を送っている.
checkout ({state, commit}) {
shop.buyProducts(
state.cart,
() => {
commit('emptyCart')
commit('setCheckoutStatus', 'success')
},
() => {
commit('setCheckoutStatus', 'fail')
}
)
}
Dynamic Vuex Getters
在庫がないときに商品名が消えてしまうのは微妙なので,Add to cart ボタンを disable にする実装をした.
(実装画面)
Vuex Map Helpers
ここからは,Vuex のお作法でリファクタリングをしていく.まずは Map Helpers で state / getters / actions
の宣言をシンプルにするために mapState / mapGetters / mapActions
を宣言し,スプレッド演算子とともに,その中に呼び出し名を宣言できる.
computed: {
...mapState({
products: state => state.products
}),
...mapGetters({
productIsInStock: 'productIsInStock'
})
}
Split Vuex Store in Multiple Files
次は store/index.js
の肥大化を防ぐために,actions だけを store/actions.js
に切り出した.ただし,ここでは切り出せることを学ぶだけで,実際には次に出てくる Vuex Modules で書き直すことになる.
Vuex Modules
モジュールも Vuex のコンポーネントで,ストアごとに切り出していくようなイメージになる.今回は store/modules/cart.js
と store/modules/products.js
に切り出した.モジュールごとに state / getters / mutations / actions
を持っているので,わかりやすいし,テストコードも書きやすそう.結果的に store/index.js
に実装はなくなり,とにかく薄くなった.
import Vuex from 'vuex'
import Vue from 'vue'
import actions from './actions'
import cart from './modules/cart'
import products from './modules/products'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
cart,
products
},
state: {
},
getters: {
},
actions,
mutations: {
}
})
Namespaced Vuex Modules
最後は namespaced で,モジュールで namespaced: true
を指定することにより,コンポーネント側で mapActions
に名前空間を指定できるようになる.メソッド名にストア名を含めて冗長になっている場合など,シンプルに書けるようになる.
まとめ
- Vue School の無料コース「Vuex for Everyone」を受講した
- ショッピングカートを実装しながら,Vuex の基礎を学べた
- 動画だと理解できなかった部分などは公式ドキュメント(日本語)を参考にした
vuex.vuejs.org
写経した GitHub リポジトリ
github.com
他にもある Vue School の無料コース
過去に受講した Firebase Realtime Database の無料コースも,Firebase Authentication の無料コースも良かった.
kakakakakku.hatenablog.com
kakakakakku.hatenablog.com