gotoshin

主に学んだ事の自分メモ用です。記事に書くまでも無いような事はhttps://scrapbox.io/study-diary/に書いてます。

nuxt×axiosでローディング処理の共通化

この記事について

nuxt×axiosのプロジェクトでローディング処理を共通化したのでその方法を記載します。 テンプレートはbootstrap-vueを使用しています。

概要

axiosを使用しているため、axiosの処理中にローディングが走る用に設定します。 手順の概要は以下です。

  1. ローディング用のコンポーネントを作成する。ローディングの表示はv-ifで表示を切り替える。また、v-ifの条件をstoreに定義し、別コンポーネントからのアクセスも可能にする( リンク
  2. 全ページ共通のdefault.vueにローディング用のコンポーネントを設定。( リンク
  3. axiosのinterceptors.request.useinterceptors.response.useを使用してaxiosの前後で、上記でstoreに定義した条件を切り替える( リンク
  4. nuxt.config.jsmodulesに設定ファイルを読み込ませる( リンク

ローディング用のコンポーネント作成

components/Loading.vue

<template>
  <div v-if="showLoading" class="d-flex justify-content-center loading-box">
    <b-spinner
      style="width: 3rem; height: 3rem;"
      label="Large Spinner"
      variant="info"
      class="loading-item"
    ></b-spinner>
  </div>

</template>
<script>
export default {
  computed: {
    showLoading(){
      return this.$store.getters['loading/showLoading']
    },
  },
}
</script>
<style scoped>
.loading-box {
  z-index: 999999;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
.loading-item {
  margin-top: 50%;
}
</style>
  • ローディングの表示はv-ifで表示を切り替える。また、v-ifの条件をstoreに定義し、別コンポーネントからのアクセスも可能にする

app/store/loading.js

export const state = () => ({
  showLoading: false
})
export const mutations = {
  loadingStart(state) {
    state.showLoading = true
  },
  loadingStop (state) {
    state.showLoading = false
  }
}
export const actions = {
  loadingStart ({commit}) {
    commit('loadingStart')
  },
  loadingStop ({commit}) {
    commit('loadingStop')
  }
}
export const getters = {
  showLoading (state) {
    return state.showLoading
  }
}

全ページ共通のdefault.vueにローディング用のコンポーネントを設定

<template>
  <div>
    <Header class="common-header"/>
    <b-container>
      <nuxt />
      <Loading />
    </b-container>
  </div>
</template>

<script>
import Header from '@/components/Header.vue';
import Loading from '@/components/Loading.vue';
export default {
  components: { Header, Loading },
}
</script>

axiosの前後でローディングの表示を切り替える

app/plugins/axios.js

export default ({store, $axios}, inject) => {
  $axios.interceptors.request.use(function (config) {
    store.dispatch('loading/loadingStart')
    config.baseURL = process.env.API_BASE_URL
    config.timeout = 160000
    return config;
  });
  $axios.interceptors.response.use(function (response) {
    store.dispatch('loading/loadingStop')
    return response;
  });
  • 先程storeに定義したアクションをequest.useresponse.useでそれぞれ呼び出す。

  • plugins配下のメソッドはコンテキストを第一引数に受け取る事が可能なため、$axiosを使用。ちなみにそうした場合、axios.createbaseURL等のデフォルトの設定が出来なかったため、今回interceptorsで定義している。(なぜaxios.createが使用出来なかったのかは不明・・・)

  • axiosのinterceptors GitHub - axios/axios: Promise based HTTP client for the browser and node.js

app/plugins/axios.js

  const apiGet = function (url, params = {}, headers = {}) {
    return $axios.get(url, {
      params: params,
    })
    .catch(err => err.response || { noResponse: true })
  }
  const apiDelete = function  (url, params = {}, headers = {}) {
    return $axios.delete(url, {
        headers: headers,
        params: params,
      })
      .catch(err => err.response || { noResponse: true })
  }

  const apiPost = function  (url, params = {}, headers = {}) {
    return $axios.$post(url, params, {
      headers: headers
    }).catch(err => err.response || { noResponse: true })
  }

  const apiPut = function  (url, params = {}, headers = {}) {
    return $axios.put(url, params, {
        headers: headers,
      })
      .catch(err => err.response || { noResponse: true })
  }

  inject('apiGet', apiGet);
  inject('apiDelete', apiDelete);
  inject('apiPost', apiPost);
  inject('apiPut', apiPut);
}
  • apiGetapiPost等のプロジェクトで使用するメソッドは、先程のinterceptorsの設定を適用する必要があるため、interceptorsを定義した同じ$axiosを使用して定義する。

  • ちなみになぜpostだけ$post(ショートカット)を使用しているかというと、通常のpostの場合headersの設定が適用されなかったため。(理由は不明・・・) Usage | Axios Module

nuxt.config.jsmodulesに設定ファイルを読み込ませる

  modules: [
    ['bootstrap-vue/nuxt', {
      icons: true,
    }],
    '@nuxtjs/axios',
  ],

追記

$axios.interceptors.response.useでエラー時にもローディングが終わるように書かないと、エラー時にずっとぐるぐるなっちゃうので注意。

$axios.interceptors.response.use(function (response) {
    store.dispatch('loading/loadingStop')
    return response;
  }, function (err) {
    store.dispatch('loading/loadingStop')
    return err;
  });