30minくらいで学ぶVue.jsとVuex
カウンターアプリケーションの開発を通じてVue.jsによるプログラミングとVuexによる状態管理を学びます。
ボタンを押したら数字が増えていくアプリケーションです。
Agenda
- Part 1 Vueアプリケーションの開発(10min)
- プロジェクトの作成
- Vueコンポーネント(MyCounter.vue)の作成
- Part 2 Vuexを活用したVueアプリケーションの開発(10min)
- Vuexのインストール
- Storeの作成
- Vueコンポーネント(MyCounter.vue)の修正
- Part 3 非同期処理(Actions)の実装(10min)
- Storeの修正
- Vueコンポーネント(MyCounter.vue)の修正
Part 1 Vueアプリケーションの開発(10min)
プロジェクトの作成
プロジェクトの雛形を作成するためにvue-cliをインストールします。
npm install -g @vue/cli
インストールしたvue-cliを使ってプロジェクトの雛形を作成します。
vue create counter-app
vue-cliの設定はデフォルトを使います。途中でVuexを追加しますが手動で追加するものとします。
プロジェクトが作成できたらディレクトリを移動してサーバを起動してみましょう。ここではyarnを使って起動しています(インストールの設定によってはnpmでも大丈夫です)。
cd counter-app yarn serve
次のような画面を確認できればOKです。
Vueコンポーネント(MyCounter.vue)の作成
vue-cliで作成したプロジェクトの開発では主にsrcディレクトリ下のファイルを編集することになります。
- src/
- assets/
- 画像ファイルなどのアセット
- components/
- App.vueからロードされる画面の部品となるVueファイル
- App.vue
- main.jsからロードされるVueファイル
- main.js
- 起動ファイル
- assets/
src/components/MyCounter.vueファイルを新規作成します。
<template> <div> Count: {{ count }} <button @click="onclick">Increment</button> </div> </template> <script> export default { data () { return { count: 1 } }, methods: { onclick () { this.count++ } } } </script>
続いてsrc/App.vueを修正します。
<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png"> - <HelloWorld msg="Welcome to Your Vue.js App"/> + <MyCounter /> </div> </template> <script> -import HelloWorld from './components/HelloWorld.vue' +import MyCounter from '@/components/MyCounter.vue' export default { name: 'app', components: { - HelloWorld + MyCounter } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
ブラウザでサーバ(localhost:8080)にアクセスすると次のような画面が表示されるでしょう。
Part 2 Vuexを活用したVueアプリケーションの開発(10min)
Vuexのインストール
つづいてVuexをインストールします。
VuexはVue.jsアプリケーションのための状態管理パターン+ライブラリです。 https://vuex.vuejs.org/ja/
$ yarn add vuex --save
ここではMyCounter.vueの状態(dataプロパティ)をVuex上で管理するように修正していきます。
Storeの作成
Vuex上で状態を管理するためのStoreファイルを作成します。src/store/index.jsを作成し、以下のように実装します。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ }, }, }) export default store
VuexのStoreには以下の主に4つを記述します。
- state・・・状態データ
- mutations・・・状態を更新する処理
- getters・・・状態を取得する処理
- actions・・・非同期処理(mutationsを呼び出す)
gettersとactionsについては後述します。
またsrc/main.jsファイルを編集してsrc/store/index.jsを読み込むよう修正します。
import Vue from 'vue' import App from './App.vue' + import store from './store' Vue.config.productionTip = false new Vue({ render: h => h(App), + store, }).$mount('#app')
Vueコンポーネント(MyCounter.vue)の修正
src/components/MyCounter.vueを次のように修正します。
<template> <div> Count: {{ count }} <button @click="onclick">Increment</button> </div> </template> <script> export default { - data () { - return { - count: 1 - } - }, + computed: { + count() { + return this.$store.state.count; + } + }, methods: { onclick () { - this.count++ + this.$store.commit('increment') } } } </script>
VueコンポーネントからStoreにアクセスするにはthis.$store
と記述します。this.$store.state.count
で状態(state)にアクセスし、状態を更新するmutationsを実行するにはcommitメソッドを使います。
ブラウザでサーバ(localhost:8080)にアクセスして正しく動作することを確認しておいてください。
mapGetters、mapMutationsによるリファクタリング
Vuexには以下のヘルパーメソッドが用意されています。
- mapState
- mapMutations
- mapGetters
- mapActions
上記のヘルパーメソッドを使うとVueコンポーネントの記述がシンプルになります。
ここではmapGettersとmapMutationsを利用するように修正してみます。
まずはsrc/store/index.jsを修正します。Storeファイルにgettersを追加します。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, + getters: { + count: state => state.count + }, mutations: { increment (state) { state.count++ }, }, }) export default store
ここでgettersは単純にstateを返却していますが、gettersはStoreの状態を算出(フィルタリングなど)する用途に使えます。
次にsrc/componetns/MyCounter.vueを修正します。
<template> <div> Count: {{ count }} - <button @click="onclick">Increment</button> + <button @click="increment">Increment</button> </div> </template> <script> +import { mapGetters, mapMutations } from 'vuex' + export default { computed: { - count() { - return this.$store.state.count; - } + ...mapGetters(['count']) }, methods: { - onclick () { - this.$store.commit('increment') - } + ...mapMutations(['increment']) } } </script>
mapMutationsやmapGettersは戻り値にオブジェクトを返すので、オブジェクトスプレッド演算子を合わせて利用します。また引数には利用したい処理を定数の配列で渡すようにします。
ブラウザでサーバ(localhost:8080)にアクセスして正しく動作することを確認しておいてください。
Part 3 非同期処理(Actions)の実装(10min)
Storeの修正
続いて非同期処理を実装してみます。ここではボタンを押してから2秒後にインクリメントするIncrement Async
ボタンを実装します。
まずはsrc/store/index.jsを修正します。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, getters: { count: state => state.count }, mutations: { increment (state) { state.count++ }, }, + actions: { + incrementAsync ({ commit }) { + setTimeout(() => commit('increment'), 2000) + } + } }) export default store
新たにactionsを定義しています。actionsではmutationsをcommitするようにします。
actionsはWeb APIの呼び出しなどに適しています。
Vueコンポーネント(MyCounter.vue)の修正
続いてsrc/components/MyCounter.vueを修正します。
<template> <div> Count: {{ count }} <button @click="increment">Increment</button> + <button @click="incrementAsync">Increment Async</button> </div> </template> <script> import { mapGetters, mapMutations } from 'vuex' export default { computed: { ...mapGetters(['count']) }, methods: { + incrementAsync () { + this.$store.dispatch({ + type: 'incrementAsync' + }) + }, ...mapMutations(['increment']) } } </script>
新たにincrementAsyncメソッドを追加しています。incrementAsyncメソッドではStoreに対してdispachメソッドを呼ぶことでactionsを呼び出しています。
ブラウザでサーバ(localhost:8080)にアクセスして正しく動作することを確認しておいてください。
mapActionsによるリファクタリング
続いてmapActionsを使ってリファクタリングしてみましょう。src/components/MyCounter.vueを修正します。
<template> <div> Count: {{ count }} <button @click="increment">Increment</button> <button @click="incrementAsync">Increment Async</button> </div> </template> <script> -import { mapGetters, mapMutations } from 'vuex' +import { mapGetters, mapMutations, mapActions } from 'vuex' export default { computed: { ...mapGetters(['count']) }, methods: { - incrementAsync () { - this.$store.dispatch({ - type: 'incrementAsync' - }) - }, + ...mapActions(['incrementAsync']), ...mapMutations(['increment']) } } </script>
ブラウザでサーバ(localhost:8080)にアクセスして正しく動作することを確認しておいてください。
まとめ
Vuexを使ってVue.jsアプリケーションの状態管理を試してみました。Vuexの詳細については公式のマニュアルを読めば大体わかります。
以降はVue Routerを理解して、Nuxt.jsの学習を進めていくと良いでしょう。