- 開発技術
Vuexで中~大規模なSPAを構築する【Vue.js】
- #VueJS

そもそもVue.jsとは?
「Vue.jsまたはVueは、Webアプリケーションにおけるユーザーインターフェイスを構築するための、オープンソースのJavaScriptフレームワークである(Wikipedia)。」
VueはJavaScriptのフレームワークで、HTML、CSS、JavaScriptの書き方を知っていれば簡単に高機能なアプリケーションを作ることができます。
何故Vuexを使うのか?
VueでSPA(シングルページアプリケーション)を構築する際、プロジェクトの規模が肥大化していくとコンポーネント間のデータの受け渡しが複雑になり管理が難しくなります。
例えばコンポーネントが多数存在し、コンポーネント間で受け渡すパラメータをpropsやemitで何度も受け渡しするとパラメータの流れを追うことが難しくなります。
Vuexを使うことでデータの管理を一元化することができ、規模の大きなプロジェクトでのデータ管理が容易となります。
VuexでWEBアプリを構築してみよう
- VueとVuexのインストール
Vue CLIを利用して初期環境の構築を行います。Vue CLIをインストールするためにnpmを使用します(npmを使用するにはNode.jsをインストールする必要がありますが今回は割愛します)。Vue CLIのインストール
npm install -g @vue/cli
下記コマンドを打ってバージョンが表示されれば成功です。
vue –version 4.1.2
プロジェクト用のでディレクトリに移動し、下記コマンドを打ってVueプロジェクトを作成します。
vue create sample-app
Manually select featuresを選択
Vue CLI v4.1.2 ┌──────────────────────────────────────────┐ │ │ │ New version available 4.1.2 → 4.5.13 │ │ Run npm i -g @vue/cli to update! │ │ │ └──────────────────────────────────────────┘ ? Please pick a preset: default (babel, eslint) ❯ Manually select features
Vuexを選択
? Please pick a preset: Manually select features ? Check the features needed for your project: ◉ Babel ◯ TypeScript ◯ Progressive Web App (PWA) Support ◯ Router ❯◉ Vuex ◯ CSS Pre-processors ◉ Linter / Formatter ◯ Unit Testing ◯ E2E Testing
下記コマンドを打ちます。
cd sample-app npm run serve
下記の表示が出たらブラウザでhttp://localhost:8080/にアクセスすると画面が表示されます。
App running at: - Local: http://localhost:8080/ - Network: http://xx.x.xxx.xx:8080/ Note that the development build is not optimized. To create a production build, run npm run build.
-
StoreでVuexの状態を管理する
Vuexではstoreでデータを管理します。src/store/index.jsの下記の記述でVuexの設定を行っていきます。Storeでの設定はどのコンポーネントからもアクセス可能になります。
※modulesは今回使用しません。export default new Vuex.Store({ state: {}, mutations: {}, actions: {}, modules: {}, });
- stateで変数を保持する
storeを設定していきます。stateはstoreの基本となるプロパティで、グローバル変数のようにどのコンポーネントからもアクセス可能な変数を定義することができます。
src/store/index.js のstateを書き換えます。export default new Vuex.Store({ state: { number: 1 }, mutations: {}, actions: {} });
src/App.vueの下記の記述は不要なので削除します。
<img alt="Vue logo" src="./assets/logo.png" />
src/components/HelloWorld.vueを書き換えます。this.$store.state をComputedプロパティに記述してstateにアクセスします。
<div> <p>{{number}}</p> </div> </template> <script> export default { computed:{ number(){ return this.$store.state.number; } } }; </script> <style scoped>
“1”が表示されます。
- gettersでstateの値を算出する
gettersはVuexで算出プロパティのように使用できます。Computedプロパティのように計算した値を返すような使い方ができます。src/store/index.jsにgettersを追加します。export default new Vuex.Store({ state: { number: 1 }, getters: { numberAdd: state => state.number + 10 }, mutations: {}, actions: {} });
src/components/HelloWorld.vueを書き換えます。
<template> <div> <p>{{number}}</p> </div> </template> <script> export default { computed:{ number(){ return this.$store.getters.numberAdd; } } }; </script> <style scoped> </style>
this.$store.gettersでgettersを呼び出すことができます。
”11”が表示されます。$store.state.number+10 のようにしても同じように表示できますが、$store.stateではstateの値を変更できてしまいます。一方gettersでは参照のみですので書き換える心配はありません。Stateの値を参照したいだけの場合は基本的にgettersを使うことが推奨されています。
mutationsでstateの値を更新する -
mutationsでstateの値を更新する
Stateの値を更新したい場合、$store.stateではなくmutationsを使います。$store.stateを使用して更新すると、どこで更新されているか追跡するのが困難になるため、Vuexでstateの更新を行う場合はmutationsで行うのが原則です。src/store/index.jsを書き換えます。
export default new Vuex.Store({ state: { number: 1 }, getters: { numberAdd: state => state.number + 10 }, mutations: { incrementNumber(state,num){ state.number += num; } }, actions: {} });
mutationsでは第1引数にstate、第2引数に好きな値をとることができます。今回はインクリメントに使用する数値をとります。
src/components/HelloWorld.vueを書き換えます。
<template> <div> <button @click="incrementNumber">+5</button> <p>{{number}}</p> </div> </template> <script> export default { computed:{ number(){ return this.$store.state.number+10; } }, methods:{ incrementNumber(){ this.$store.commit("incrementNumber",5); } } }; </script> <style scoped> </style>
MethodsにincrementNumberを定義し、その中でthis.$store.commitと記述することでmutationsを呼び出します。第1引数にmutationsのプロパティ名を、第2引数にmutations のincrementNumberに渡す引数を設定します。
ボタンのクリックイベントにincrementNumberを定義すると、クリックで数値が加算されます -
actionで非同期処理を行う
mutationsでは非同期処理を扱えないため、非同期処理を行たい場合はactionsを使用します。src/store/index.jsを書き換えます。
export default new Vuex.Store({ state: { number: 1 }, getters: { numberAdd: state => state.number + 10 }, mutations: { incrementNumber(state,num){ state.number += num; } }, actions: { incrementNumber(context,number){ setTimeout(() => { context.commit('incrementNumber',number) }, 4000); } } });
actionsにincrementNumberを定義します。actionsの第一引数のcontextはcontext.commitと記述してmutationを呼び出したり、context.stateでstateにアクセスできたりします。
今回はsetTimeoutで非同期処理を作り、その中でcontext.commitを記述してmutationのincrementNumberを呼び出します。
src/components/HelloWorld.vueを書き換えます。
<template> <div> <button @click="incrementNumber">+5</button> <p>{{number}}</p> </div> </template> <script> export default { computed:{ number(){ return this.$store.state.number+10; } }, methods:{ incrementNumber(){ this.$store.dispatch("incrementNumber",5); } } }; </script> <style scoped> </style>
this.$store.dispatchと記述することでactionを呼び出すことができます。
ボタンをクリックすると4秒後に数値が加算され、非同期処理が行われることがわかります。
Vuexの全体像、データフローについて
データフローは下記の図にようになっています。コンポーネントからActionsまたmutationsでstateの値を更新し、図には書かれていないですがgettersを使ってコンポーネントにstateの値を表示するといったフローが基本となります。