以前書いた記事
React、Reduxとaxiosを使って郵便番号から住所を取得する
のvue.jsバージョンです。
vueはまだまだ初心者なため間違っている部分など多々あると思いますのでご指摘いただければと思います。
環境構築
Vueでstateの管理はどうやるのかなと色々と調べてみたところ、Vuex
という、ReactでいうところのReduxに相当するものがあるようです。
今回はVuexを使って非同期処理を行っていきます。
vuexの導入は前回の記事
はじめてVue.jsを触ってみた
でも使用した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に不要なものがごちゃごちゃ書かれていて邪魔なので
もっとシンプルなものに書き換えておきます。
<template>
<div>
<HelloWorld />
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
name: "app",
components: {
HelloWorld
}
};
</script>
storeを書き換える
今回も前回と同様、こちらのサービスを使用させて頂きました。
郵便番号-住所検索API
storeは初期の状態だと以下のように書かれています。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
}
})
state
の項目にstateの初期値を、mutations
にstoreの状態を変更する処理を、action
に非同期処理を書いていくらしいです。
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
が取得した住所になります。
context.commit("getAddress", payload);
このようにmutationsをコミットすることで非同期処理の結果をstoreに反映させているらしいです。
コンポーネントを編集
初期設定の段階で作成されている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の値をコンポーネントで使用する時は
this.$store.state.zip.address
このように書けば値が取得できるようです。
参考
Vuex 入門
Vuexのアクションを理解する
Vuexを用いたVue.jsアプリケーションのシンプルな状態管理とデータフロー