Vuex:mapStateの書き方8パターン+11サンプルコード

VuexのmapStateは書き方にバリエーションがある。ここではできるだけ多くのパターンを紹介する。

まず、話を具体的にするために次のようなストアを前提にする。

const profile = {
  namespaced: true,
  state: { twitter: "@suin", facebook: null, text: "よろしく〜" }
};

const user = {
  namespaced: true,
  state: { name: "suin" },
  modules: { profile }
};

const post = {
  namespaced: true,
  state: {
    title: "VuexのmapStateの書き方",
    tags: ["JavaScript", "Vue", "Vuex"]
  }
};

const store = new Store({
  state: { isLoggedIn: true },
  modules: { user, post }
});

従って、ストアのステートは次の図示のようになる。isLoggedInはルート直下のステートで、モジュールではない。userprofilepostはモジュールだ。userprofileはネストした構造にした。

なお、以下で示すサンプルコードの実行はCodePenのVuex: mapState patternsで行った。

mapStateを使う前のおまじない(定型文)

VueコンポーネントでmapStateを使うためには、vuexライブラリからmapStateをインポートする必要がある。コンポーネントの<script>タグのあたまに書いておこう。

<script>
import {mapState} from 'vuex'
...

mapStateの書き方パターン集

:one: 普通のバインド

通常のバインドの書き方。

構文
computed: mapState(["ステートのキー"])
// 複数のステートをバインドすることもできる
computed: mapState(["ステートのキー", "ステートのキー", ...])

:warning: 次のような配列でない使い方はできず、Uncaught TypeError: Cannot convert undefined or null to objectというエラーが発生する。

mapState("ステートのキー") // エラー

isLoggedInをバインドする例

const app = {
  name: "app",
  computed: mapState(["isLoggedIn"]),
  template: `<p>{{isLoggedIn}}</p>`
};
バインドされた状態
isLoggedIn: true

isLoggedInuserをバインドする例

const app = {
  name: "app",
  computed: mapState(["isLoggedIn", "user"]),
  template: `<p>{{isLoggedIn}}{{user}}</p>`
};
バインドされた状態
isLoggedIn: true
user:
  name: "suin"
  profile:
    facebook: null
    text: "よろしく〜"
    twitter: "@suin"

:two: 別名のバインド

ストアのステートを別名でバインドする書き方。

構文
computed: mapState({
  別名: "ステートのキー"
})
// 複数のステートをバインドすることもできる
computed: mapState({
  別名: "ステートのキー",
  別名: "ステートのキー",
  ...
})

isLoggedInisSignedInと呼称しつつバインドする例

const app = {
  name: "app",
  computed: mapState({
    isSignedIn: "isLoggedIn"
  }),
  template: `<p>{{isSignedIn}}</p>`
};
バインドされた状態
isSignedIn: true

:three: モジュール内のステートのバインド

構文
computed: mapState("モジュールのパス", ["モジュール内のステートのキー"])
// モジュール内の複数のステートをバインドすることもできる
computed: mapState("モジュールのパス", ["モジュール内のステートのキー", "モジュール内のステートのキー", ...])

user.profileをバインドする例

const app = {
  name: "app",
  computed: mapState("user", ["profile"]),
  template: `<p>{{profile}}</p>`
};
バインドされた状態
profile:
  facebook:null
  text: "よろしく〜"
  twitter: "@suin"

user.profile.twitterをバインドする例

const app = {
  name: "app",
  computed: mapState("user/profile", ["twitter"]),
  template: `<p>{{twitter}}</p>`
};
バインドされた状態
twitter: "@suin"

user.profile.textuser.profile.twitterをバインドする例

const app = {
  name: "app",
  computed: mapState("user/profile", ["text", "twitter"]),
  template: `<p>{{text}}{{twitter}}</p>`
};
バインドされた状態
text: "よろしく〜"
twitter: "@suin"

:four: 算出プロパティとステートの共存

オブジェクトスプレッド演算子(...)を使う必要がある。

構文
computed: {
  ...mapState(["ルートステートのキー"]),
  算出プロパティ1() { /* ... */ },
  算出プロパティ2() { /* ... */ },
  ...
}

算出プロパティがあるコンポーネントにisLoggedInをバインドする例

const app = {
  name: "app",
  computed: {
    ...mapState(["isLoggedIn"]),
    date() {
      return new Date()
    }
  },
  template: `<p>{{isLoggedIn}} {{date}}</p>`
};
算出プロパティ
date: "2018-01-07T11:11:03.779Z"
バインドされた状態
isLoggedIn: true

:five: 複数モジュールのモジュール内ステートのバインド

オブジェクトスプレッド演算子(...)を使う必要がある。

構文
computed: {
  ...mapState("モジュール名", ["モジュールステートのキー"]),
  ...mapState("モジュール名", ["モジュールステートのキー"]),
  ...
}

user.namepost.titlepost.tagsをバインドする例

const app = {
  name: "app",
  computed: {
    ...mapState("user", ["name"]),
    ...mapState("post", ["title", "tags"])
  },
  template: `<p>{{name}} {{title}} {{tags}}</p>`
};
バインドされた状態
name: "suin"
tags: 
  0: "JavaScript"
  1: "Vue"
  2: "Vuex"
title: "VuexのmapStateの書き方"

:six: モジュール内ステートの別名バインド

構文
computed: mapState("モジュールのパス", {
  別名: "モジュール内のステートのキー"
})

user.nameuserNameと呼称しながらバインドする例

const app = {
  name: "app",
  computed: mapState("user", {
    userName: "name"
  }),
  template: `<p>{{userName}}</p>`
};
バインドされた状態
userName: "suin"

:seven: ステート加工結果のバインド

ステートをそのままバインドするのではなく、ステートを加工した結果をバインドする方法。

構文
computed: mapState({
  加工後の名称: state => 加工処理(state.加工対象のステート名)
})

isLoggedInを加工した結果をisLoggedOutとしてバインドする例

const app = {
  name: "app",
  computed: mapState({
    isLoggedOut: state => !state.isLoggedIn
  }),
  template: `<p>{{isLoggedOut}}</p>`
};
バインドされた状態
isLoggedOut: false

:eight: 複雑なバインド

モジュールをまたいだ複雑なバインドをする方法。

isLoggedInuser.namepost.titleをバインドする例

const app = {
  name: "app",
  computed: mapState({
    isLoggedIn: "isLoggedIn",
    userName: state => state.user.name,
    postTitle: state => state.post.title
  }),
  template: `<p>{{isLoggedIn}} {{userName}} {{postTitle}}</p>`
};
バインドされた状態
isLoggedIn: true
postTitle: "VuexのmapStateの書き方"
userName: "suin"

質疑応答

質問などは、ここにコメントを残すかsuinのプログラミング相談室(チャット)で話しかけてください。どんな些細なものでも構いません。