以前にこちらの記事を投稿したんですが、今回はVue CLI
で同じことを試してみます。
【Vuex】CDNでVuexの最初の一歩を踏み出す
Vue CLIのプロジェクト作成
前提として、Vue CLIの起動に必要なパッケージは全てグローバルインストールされている状態です。
【Vue.js】Vue CLIでVue.jsを動かす〜プロジェクト作成まで
$ vue init webpack my_vuex_test
Vuexのインストール
$ npm install vuex
インストール後にパッケージの脆弱性や依存情報についてメッセージが出力されますが、学習用のため、今回はこのまま進めました。
ディレクトリ構造
srcディレクトリ
直下の既存ファイルを若干編集しています。
使用しているファイルに限定すると、以下の構造になります。
src
├── components
│ ├── App.vue // 編集
│ └── Counter.vue // 新規ファイル
├── main.js // 編集
└── store // 新規ディレクトリ
└── index.js // 新規ファイル
// 最終的に、ルートディレクトリ直下の``index.html``により出力される
用語の確認
簡単に確認します。
内容は公式サイトからの引用です。
説明だけだと分かりにくいので、実際に使いながら覚えていきます・・・
ストア
信頼できる唯一の情報源。
アプリ1つにつき、1つだけ作ることができる。
Vuex アプリケーションの中心にあるものはストアです。"ストア" は、基本的にアプリケーションの 状態(state) を保持するコンテナです。
ステート
ストアの状態そのもの。
ストアの状態はここから呼び出される。
Vuex は 単一ステートツリー (single state tree) を使います。つまり、この単一なオブジェクトはアプリケーションレベルの状態が全て含まれており、"信頼できる唯一の情報源 (single source of truth)" として機能します。これは、通常、アプリケーションごとに1つしかストアは持たないことを意味します。単一ステートツリーは状態の特定の部分を見つけること、デバッグのために現在のアプリケーションの状態のスナップショットを撮ることを容易にします。
ミューテーション
ストアの状態を変更する手段。
実際に Vuex のストアの状態を変更できる唯一の方法は、ミューテーションをコミットすることです。Vuex のミューテーションはイベントにとても近い概念です: 各ミューテーションはタイプとハンドラを持ちます。ハンドラ関数は Vuex の状態(state)を第1引数として取得し、実際に状態の変更を行います。
ソースコード
処理の流れ
このようになるかと思います。
-
store/index.js
でストアをセットする -
main.js
でストアをimportする - main.jsに
storeオプション
を設定し、コンポーネントにストアを注入する - 同じくmain.jsでimportしている
App.vue
に、注入されたストアが反映される - App.vueからimportしている
Counter.vue
にも、注入されたストアが反映される
公式サイトより引用します。
ルートインスタンスに store オプションを渡すことで、渡されたストアをルートの全ての子コンポーネントに注入します。これは this.$store で各コンポーネントから参照することができます。
ルートのmain.jsでstoreオプション
を使用することにより、枝葉であるコンポーネントへストアが注入されます。
注入されたストアは、this.$store.state.count
という書き方でApp.vueとCounter.vueの双方から呼び出しています。
store/index.jsとmain.jsでstore.commit('increment')
を行なっているため、最終的にcount
の結果は2
になります。
npm run dev
でサーバーを立ち上げると、ブラウザ上で確認できます。
index.html
特に編集はしていません。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>my_vuex_test</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
main.js
import Vue from 'vue';
import Vuex from 'vuex';
// index.jsの場合はファイル名を指定する必要はない
import store from './store'
import App from './components/App'
Vue.use(Vuex);
new Vue({
el: '#app',
store,
components: { App },
template: '<App/>' // '<app></app>'でも可
})
store.commit('increment')
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++
}
}
})
store.commit('increment')
export default store
App.vue
<template>
<div id="app">
<p>App: {{ count }}</p>
<Counter/>
</div>
</template>
<script>
import Counter from './Counter'
const App = {
components: {
Counter
},
computed: {
count() {
return this.$store.state.count
}
}
}
export default App
</script>
Counter.vue
<template>
<div id="counter">
<p>Counter: {{ count }}</p>
</div>
</template>
<script>
const Counter = {
computed: {
count() {
return this.$store.state.count
}
}
}
export default Counter
</script>
Vuexには他にもgettersなどの機能がありますが、少しずつ進めていきます。