nuxt×axiosでローディング処理の共通化
この記事について
nuxt×axiosのプロジェクトでローディング処理を共通化したのでその方法を記載します。
テンプレートはbootstrap-vue
を使用しています。
概要
axiosを使用しているため、axiosの処理中にローディングが走る用に設定します。 手順の概要は以下です。
- ローディング用のコンポーネントを作成する。ローディングの表示は
v-if
で表示を切り替える。また、v-if
の条件をstore
に定義し、別コンポーネントからのアクセスも可能にする( リンク) - 全ページ共通の
default.vue
にローディング用のコンポーネントを設定。( リンク) - axiosの
interceptors.request.use
とinterceptors.response.use
を使用してaxios
の前後で、上記でstore
に定義した条件を切り替える( リンク) nuxt.config.js
のmodules
に設定ファイルを読み込ませる( リンク)
ローディング用のコンポーネント作成
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.use
・response.use
でそれぞれ呼び出す。plugins配下のメソッドはコンテキストを第一引数に受け取る事が可能なため、
$axios
を使用。ちなみにそうした場合、axios.create
でbaseURL
等のデフォルトの設定が出来なかったため、今回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); }
apiGet
やapiPost
等のプロジェクトで使用するメソッドは、先程のinterceptors
の設定を適用する必要があるため、interceptors
を定義した同じ$axios
を使用して定義する。ちなみになぜpostだけ
$post
(ショートカット)を使用しているかというと、通常のpost
の場合headers
の設定が適用されなかったため。(理由は不明・・・) Usage | Axios Module
nuxt.config.js
のmodules
に設定ファイルを読み込ませる
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; });