LoginSignup
7
8

More than 3 years have passed since last update.

Nuxtを使ってPromise, async/awaitのコードを書く

Posted at

動機

なお、サンプルコードは上のリンクのコードを用いる(下に転載)が、少し機能を変えて、
1. inputタグ内の文字列を,区切りでリスト化する
2. hogeという文字列から始まっていればその文字列を、それ以外はfugaという文字列を結果に格納
3. 結果を1つずつ表示する

という風にしている。

fetchResources.js
function dummyFetch(path) {
    return new Promise(function(resolve, reject){
        setTimeout(function(){
            if (path.startsWith("/resource")) {
                resolve({ body: `Response body of ${path}` });
            } else {
                reject(new Error("NOT FOUND"));
            }
        }, 1000 * Math.random());
    });
}

// 複数のリソースを取得しレスポンスボディの配列を返す
async function fetchResources(resources) {
    // リソースをまとめて取得する
    const promises = resources.map(function(resource){
        return dummyFetch(resource);
    });
    // すべてのリソースが取得できるまで待つ
    // Promise.allは [ResponseA, ResponseB] のように結果が配列となる
    const responses = await Promise.all(promises);
    // 取得した結果からレスポンスのボディだけを取り出す
    return responses.map(function(response){
        return response.body;
    });
}
const resources = ["/resource/A", "/resource/B"];
// リソースを取得して出力する
fetchResources(resources).then(function(results){
    console.log(results); // => ["Response body of /resource/A", "Response body of /resource/B"]
});

1ファイル内で完結させる実装

まずはvuexのStore機能を使わず、dummy.vueファイル内のみで完結させる

pages/dummy.vue
<template>
  <div>
    <!-- 送信用 -->
    <div>
      <input v-model="resources" type="text">
      <button @click="submit">
        送信
      </button>
    </div>
    <!-- 表示用 -->
    <div>
      <ul>
        <li v-for="(result, index) in results" :key="index">
          {{ result }}
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      resources: '',
      results: []
    }
  },
  methods: {
    async submit() {
      const resources = this.resources.split(',')
      const promises = resources.map((resource) => {
        return this.dummyFetch(resource)
      })
      const responses = await Promise.all(promises)
      return responses.map((response) => {
        this.results.push(response.body)
      })
    },
    dummyFetch(resource) {
      return new Promise((resolve) => {
        setTimeout(() => {
          if (resource.startsWith('hoge')) {
            resolve({ body: resource })
          } else {
            resolve({ body: 'fuga' })
          }
        }, 1000 * Math.random())
      })
    }
  }
}
</script>

挙動はこんな感じ
わかりにくいですが、上の文字列が自分で打った文字列(入力)、下のリストが結果です。
スクリーンショット 2019-05-29 15.09.51.png

Store機能を使って実装する

NuxtにおけるStoreは、2つの書き方があります、

・モジュールモード: store ディレクトリ内のすべての *.js ファイルが 名前空間付きモジュール に変換されます(index はルートモジュールとして存在します)
・クラシックモード(廃止予定): store/index.js がストアインスタンスを返します

(上のリンクより)

クラシックモードで書かれているコードが多いと思いますが、廃止予定とあったので今回はモジュールモードを使ってStore機能を使用します。
また、vueファイル内の<template>は全く同じなので割愛します

dummy.vue
<script>
import { mapActions, mapState } from 'vuex'

export default {
  data() {
    return {
      resources: ''
    }
  },
  computed: {
    ...mapState('dummy', ['results'])
  },
  methods: {
    // `this.fetch()` を `this.$store.dispatch('dummy/fetch')` にマッピング
    ...mapActions('dummy', ['fetch']),
    submit() {
      this.fetch(this.resources)
    }
  }
}
</script>
store/dummy.js
export const state = () => ({
  results: []
})

export const mutations = {
  fetchResources(state, results) {
    // state.results.push(response.body)
    state.results = results
  }
}

function dummyFetch(resource) {
  return new Promise((resolve) => {
    setTimeout(() => {
      if (resource.startsWith('hoge')) {
        resolve({ body: resource })
      } else {
        resolve({ body: 'fuga' })
      }
    }, 1000 * Math.random())
  })
}

async function fetchResources(resources) {
  const promises = resources.split(',').map((resource) => {
    return dummyFetch(resource)
  })
  const responses = await Promise.all(promises)
  return responses.map((response) => {
    return response.body
  })
}

export const actions = {
  fetch({ commit }, resources) {
    fetchResources(resources).then((results) => {
      commit('fetchResources', results)
    })
  }
}

store内のresultsに対して、action, mutationを用いて結果を格納し、それを描画しています。

最後に

dummyFetch, fetchResources関数はどこに置けばよいのかがわからなかった。
一旦は呼び出しができるようにファイル内にかきましたが、pluginsディレクトリ内にutils.jsなどをおいて書いていけばいいのか、そのほかに方法があるのか...
わかる方、教えていただけますと幸いです。

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8