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

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

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

```js
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`はルート直下のステートで、モジュールではない。`user`と`profile`、`post`はモジュールだ。`user`と`profile`はネストした構造にした。

<img width="333" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/889/f3ec41db-352e-6cbe-5abd-718ea49f7e18.png">

なお、以下で示すサンプルコードの実行は[CodePenのVuex: mapState patterns](https://codepen.io/suin/pen/aEVQOo)で行った。

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

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

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

## mapStateの書き方パターン集

### __:one: 普通のバインド__

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

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

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

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

#### `isLoggedIn`をバインドする例

```js
const app = {
  name: "app",
  computed: mapState(["isLoggedIn"]),
  template: `<p>{{isLoggedIn}}</p>`
};
```

```yaml:バインドされた状態
isLoggedIn: true
```

#### `isLoggedIn`と`user`をバインドする例

```js
const app = {
  name: "app",
  computed: mapState(["isLoggedIn", "user"]),
  template: `<p>{{isLoggedIn}}{{user}}</p>`
};
```

```yaml:バインドされた状態
isLoggedIn: true
user:
  name: "suin"
  profile:
    facebook: null
    text: "よろしく〜"
    twitter: "@suin"
```

### __:two: 別名のバインド__

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

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

#### `isLoggedIn`を`isSignedIn`と呼称しつつバインドする例

```js
const app = {
  name: "app",
  computed: mapState({
    isSignedIn: "isLoggedIn"
  }),
  template: `<p>{{isSignedIn}}</p>`
};
```

```yaml:バインドされた状態
isSignedIn: true
```

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

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

#### `user.profile`をバインドする例

```js
const app = {
  name: "app",
  computed: mapState("user", ["profile"]),
  template: `<p>{{profile}}</p>`
};
```

```yaml:バインドされた状態
profile:
  facebook:null
  text: "よろしく〜"
  twitter: "@suin"
```

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

```js
const app = {
  name: "app",
  computed: mapState("user/profile", ["twitter"]),
  template: `<p>{{twitter}}</p>`
};
```

```yaml:バインドされた状態
twitter: "@suin"
```

#### `user.profile.text`と`user.profile.twitter`をバインドする例

```js
const app = {
  name: "app",
  computed: mapState("user/profile", ["text", "twitter"]),
  template: `<p>{{text}}{{twitter}}</p>`
};
```

```yaml:バインドされた状態
text: "よろしく〜"
twitter: "@suin"
```

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

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

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

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

```js
const app = {
  name: "app",
  computed: {
    ...mapState(["isLoggedIn"]),
    date() {
      return new Date()
    }
  },
  template: `<p>{{isLoggedIn}} {{date}}</p>`
};
```

```yaml:算出プロパティ
date: "2018-01-07T11:11:03.779Z"
```

```yaml:バインドされた状態
isLoggedIn: true
```

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

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

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

#### `user.name`と`post.title`、`post.tags`をバインドする例

```js
const app = {
  name: "app",
  computed: {
    ...mapState("user", ["name"]),
    ...mapState("post", ["title", "tags"])
  },
  template: `<p>{{name}} {{title}} {{tags}}</p>`
};
```

```yaml:バインドされた状態
name: "suin"
tags: 
  0: "JavaScript"
  1: "Vue"
  2: "Vuex"
title: "VuexのmapStateの書き方"
```

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

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

#### `user.name`を`userName`と呼称しながらバインドする例

```js
const app = {
  name: "app",
  computed: mapState("user", {
    userName: "name"
  }),
  template: `<p>{{userName}}</p>`
};
```

```yaml:バインドされた状態
userName: "suin"
```

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

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

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

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

```js
const app = {
  name: "app",
  computed: mapState({
    isLoggedOut: state => !state.isLoggedIn
  }),
  template: `<p>{{isLoggedOut}}</p>`
};
```

```yaml:バインドされた状態
isLoggedOut: false
```

### __:eight: 複雑なバインド__

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

#### `isLoggedIn`、`user.name`、`post.title`をバインドする例

```js
const app = {
  name: "app",
  computed: mapState({
    isLoggedIn: "isLoggedIn",
    userName: state => state.user.name,
    postTitle: state => state.post.title
  }),
  template: `<p>{{isLoggedIn}} {{userName}} {{postTitle}}</p>`
};
```

```yaml:バインドされた状態
isLoggedIn: true
postTitle: "VuexのmapStateの書き方"
userName: "suin"
```

## 質疑応答

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