Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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のプログラミング相談室(チャット)で話しかけてください。どんな些細なものでも構いません。

suin
Qiita 4位/TypeScript入門書執筆中/TypeScripterのための座談会「YYTypeScript」主催/『実践ドメイン駆動設計』書籍邦訳レビュア/分報Slack考案/YYPHP主催/CodeIQマガジン執筆/株式会社クラフトマンソフトウェア創設/Web自動テスト「ShouldBee」の開発/TypeScript/DDD/OOP
https://yyts.connpass.com/
craftsman_software
「インフラの心配は、もうおしまい」 インフラ運用を自動化し、手作業を限りなくゼロにする会社
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away