Vue、Vuexとaxiosを使って郵便番号から住所を取得する

以前書いた記事
[React、Reduxとaxiosを使って郵便番号から住所を取得する](https://qiita.com/oda3104/items/317a1309183d50061a6e)
のvue.jsバージョンです。
vueはまだまだ初心者なため間違っている部分など多々あると思いますのでご指摘いただければと思います。

##環境構築
Vueでstateの管理はどうやるのかなと色々と調べてみたところ、`Vuex`という、ReactでいうところのReduxに相当するものがあるようです。
今回はVuexを使って非同期処理を行っていきます。

vuexの導入は前回の記事
[はじめてVue.jsを触ってみた](https://qiita.com/oda3104/items/76df565b6a3e27e750bc)
でも使用した`vue-cli`を使えばとても簡単に導入できます。

プロジェクトを作成する時に

```
? Please pick a preset: 
  default (babel, eslint) 
❯ Manually select features 
```

ここで`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
```

ここで`Vuex`にチェックを入れてプロジェクトを作成します。
プロジェクトが作成された段階で自動でstoreが作られています。

この時点でReactよりだいぶ楽ですね…

初期設定のままだとApp.vueに不要なものがごちゃごちゃ書かれていて邪魔なので
もっとシンプルなものに書き換えておきます。

```vuejs:App.vue
<template>
  <div>
    <HelloWorld />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  name: "app",
  components: {
    HelloWorld
  }
};
</script>
```

##storeを書き換える

今回も前回と同様、こちらのサービスを使用させて頂きました。
[郵便番号-住所検索API](https://zipaddress.net/)

storeは初期の状態だと以下のように書かれています。

```javascript:store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {

  },
  mutations: {

  },
  actions: {

  }
})
```

`state`の項目にstateの初期値を、`mutations`にstoreの状態を変更する処理を、`action`に非同期処理を書いていくらしいです。

```javascript:store.js
import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    address: "",
    zip: ""
  },
  mutations: {
    getAddress(state, zip, address) {
      state.zip = zip;
      state.address = address;
    }
  },
  actions: {
    async getAddressAction(context) {
      const payload = {
        address: "",
        zip: context.state.zip
      };
      await axios
        .get("https://api.zipaddress.net/?", {
          params: { zipcode: payload.zip }
        })
        .then(res => {
          payload.address = res.data.data.fullAddress;
        });
      context.commit("getAddress", payload);
    }
  }
});
```

試行錯誤の結果このような形になりました。
`zip`がテキストボックスに入力された郵便番号の値、`address`が取得した住所になります。

```javascript
context.commit("getAddress", payload);
```
このようにmutationsをコミットすることで非同期処理の結果をstoreに反映させているらしいです。

##コンポーネントを編集
初期設定の段階で作成されている`HelloWorld.vue`を書き換えていきます。

```vuejs:HelloWorld.vue
<template>
  <div>
    <p>住所: {{ address }}</p>
    <input type="text" v-model="zip" />
    <button @click="getAddress">検索</button>
  </div>
</template>

<script>
import { mapState } from "vuex";

export default {
  name: "HelloWorld",
  data() {
    return {
      zip: ""
    };
  },
  computed: {
    ...mapState({
      zip: state => state.zip
    }),
    address() {
      return this.$store.state.zip.address;
    }
  },
  methods: {
    getAddress() {
      this.$store.commit("getAddress", this.zip);
      this.$store.dispatch("getAddressAction");
    }
  }
};
</script>
```

テキストボックスに入力されたzipの値をstoreにコミットし、
store.jsに書いたアクションをディスパッチしています。

storeの値をコンポーネントで使用する時は

```vuejs
this.$store.state.zip.address
```
このように書けば値が取得できるようです。

これでテキストボックスに書かれた値が正しく取得されました。
<img width="377" alt="スクリーンショット 2019-08-26 18.29.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439548/da8996de-9567-cb10-fa6b-8669eda3cc33.png">

##参考
[Vuex 入門](https://vuex.vuejs.org/ja/guide/)
[Vuexのアクションを理解する](https://junpeko.com/vuex-actions/)
[Vuexを用いたVue.jsアプリケーションのシンプルな状態管理とデータフロー](https://www.ritolab.com/entry/178)