nuxtにおけるvuexのしくみまとめ
vuexとは?
vuex
とは、公式曰く「状態管理パターン + ライブラリ」です。
共有したい状態を管理したい時に一括で状態管理ができるため、コンポーネント間のデータのやりとりを簡易化します。
state
state
は、ストアオブジェクトの状態を保持することができるプロパティ。
mapStateヘルパー
mapState
はstate
を一括で便利に扱えるようになるもの。
// before
computed: {
hoge() {
return this.$store.state.hoge;
},
fuga() {
return this.$store.state.fuga;
},
},
// after
import { mapState } from 'vuex'
export default {
computed: ...mapState({
hoge, fuga
})
}
getter
getter
は、ストア内で定義できるゲッター。いわゆる、ゲッター。computed
と同じように、依存関係の一部が変更されたときにのみ再計算される- アロー関数と相性が良い。(
return
が省略できるから。) - Vuex で modules を利用した際の getters の使い方が参考になりそう。
mapGettersヘルパー
- ストアのゲッターを一括で使えるようにできるやつ
- 使い方はstateと一緒。
mutation
mutation
はstate
の内容を変えれる場所。セッター的なやつ...?state
の変更は必ずmutation
で行う。(データの変更を予測・追跡しやすくするため)- 第一引数は
state
。第二引数以降は自由に設定可能。 - 直接ミューテーションハンドラを呼び出すことはできず、
store.commit('ミューテーション名', 第二引数以降)
でイベントを登録するような感じで呼び出すことができる。 mutation
は非同期的な処理がかけない...! 常に同期的。- 状態の変更が同期なのか非同期なのか、予測ができなくなるのを回避するため。
- 非同期の処理では
action
を使う。
mapMutationsヘルパー
- ストアのミューテーションを一括で使えるようにするやつ
- 使い方はstateと一緒。
action
- アクションは、状態を変更するのではなく、ミューテーションをコミットするもの。
- 非同期処理を含むことができるのが最大の特徴。
- 第一引数は
context
(分割代入のショートハンドで使いたいやつだけ取ってくることも可能)。第二引数以降は自由に設定可能。context
には、commit
やstate
、dispatch
などをとることができる。
- アクションは
store.dispatch
がトリガーとなって実行される。 - 直接アクションを呼び出すことはできず、
store.dispatch('アクション名', 第二引数以降)
でイベントを登録するような感じで呼び出すことができる。
mapActionsヘルパー
- ストアのアクションを一括で使えるようにするやつ
- 使い方はstateと一緒。
nuxtServerInitアクション
- アプリケーションがロードされたとき、サーバーサイドで実行される。
- サーバーサイドからクライアントサイドに直接渡したいデータがあるときに使う。
- ルートモジュール(store/index.js)でしか使えない。
実際のコードとその説明
cheezBlogにおける、全タグの管理の流れを説明してみる。
- store/index.js
// storeディレクトリ内のすべての *.js ファイルが名前空間付きモジュールに変換される
// index.jsはルートモジュールとして存在する
// contentfulのAPIから非同期でタグのデータを取得するためのプラグインをインポート
import createClient from '@/plugins/contentful.js';
const client = createClient;
/*
* state
*/
// 一旦空の状態で準備。
export const state = () => ({
tags: [{ id: '', name: '' }],
});
/*
* mutations
*/
export const mutations = {
// state.tagsの中身を書き換えることができる。
// 今回はAPIを叩いてるため、同期処理しかできないmutationをcommitするだけじゃ使えない。
SET_TAGS(state, tags) {
state.tags = tags;
},
};
/*
* actions
*/
export const actions = {
// アプリケーションがロードされたときに、サーバーサイド側で処理
async nuxtServerInit({ dispatch }) {
// actionを発火させる
await dispatch('getTags');
},
// getTagsはclient.getEntries(config)が取得できた際に実行。
async getTags({ commit }) {
const config = {
content_type: 'articleTag',
order: '-sys.createdAt',
};
const { items } = await client.getEntries(config);
const tags = items.map(({ fields, sys }) => ({
id: sys.id,
name: fields.name,
}));
// mutationを実行
commit('SET_TAGS', tags);
},
};
- TagsList.vue
<template>
...
</template>
<script>
import { mapState } from 'vuex';
export default {
computed: {
// $store.state.tagsを取得
...mapState(['tags']),
},
};
</script>