VueでLoading状態を管理する方法
公開日
2024年12月9日
更新日
2025年1月30日
7
分で読める
Vue
フロントエンドとバックエンド間の通信では、プロセスが進行中であることをユーザーに伝えるためにローディング状態を表示することが一般的です。しかし、Axiosを使ったリクエストが複数箇所に存在するプロジェクトでは、リクエストの前後にローディング処理を手動で追加すると、コードが冗長になり、保守性が低下してしまいます。
この問題を解決するために、Element PlusとAxiosをベースにした再利用可能なローディングフックコンポーネントを設計しました。このソリューションは、コードの簡略化と再利用性の向上に寄与します。以下に、実装と使い方を詳しく説明します。
実装
このフックは、ローディングロジックを一元管理し、以下の機能を提供します:
- 一般的なローディング状態の管理。
- 複数の非同期リクエストを一括で処理。
- 全画面ローディング効果のサポート(グローバルオーバーレイに最適)。
フックの実装コード
import { ref } from 'vue'
import { ElLoading } from 'element-plus'
type Options = {
/** 初期値 */
initialValue?: boolean
}
export function useLoading({ initialValue = false }: Options = {}) {
/** ローディング状態 */
const isLoading = ref(initialValue)
/**
* ローディング開始
*/
const startLoading = () => {
isLoading.value = true
}
/**
* ローディング終了
*/
const stopLoading = () => {
isLoading.value = false
}
/**
* 複数の非同期リクエストを処理
* @param promises 非同期リクエストリスト
* @returns 全リクエストの結果
*/
const withLoading = async <T>(promises: Array<() => Promise<T>>) => {
startLoading()
try {
return await Promise.all(promises.map((promise) => promise()))
} finally {
stopLoading()
}
}
/**
* 複数の非同期リクエストを全画面ローディングで処理
* @param promises 非同期リクエストリスト
* @returns 全リクエストの結果
*/
const withFullscreenLoading = async <T>(promises: Array<() => Promise<T>>) => {
startLoading()
const loading = ElLoading.service({ fullscreen: true })
try {
return await Promise.all(promises.map((promise) => promise()))
} finally {
stopLoading()
loading.close()
}
}
return { isLoading, startLoading, stopLoading, withLoading, withFullscreenLoading }
}
使用例
以下は、Vueコンポーネント内でuseLoadingフックを使ってローディング状態を管理する方法を示した完全な例です。
<template>
<div class="wrapper">
<button @click="clickHandler">日本の祝日を取得</button>
<hr />
<p>{{ JSON.stringify(holidayList) }}</p>
</div>
</template>
<script setup lang="ts">
import { useLoading } from '@/hooks/use-loading.hook'
import axios from 'axios'
import { ref } from 'vue'
// useLoadingフックを使用
const { withFullscreenLoading } = useLoading()
const holidayList = ref<any>({})
// リクエストロジックをカプセル化
const requestJapaneseHoliday = async () => {
const resp = await axios.get('https://holidays-jp.github.io/api/v1/date.json')
return resp.data
}
// ボタンクリックイベント
const clickHandler = async () => {
const [data] = await withFullscreenLoading([requestJapaneseHoliday])
holidayList.value = data
}
</script>
メリット
- ロジックの分離 ローディング状態管理をフックに抽出することで、各リクエストでstart/stopロジックを繰り返す必要がなくなり、コードが簡潔で明瞭になります。
- 同時リクエスト対応 単一のリクエストでも複数の非同期リクエストでも、
withLoadingやwithFullscreenLoadingを使えば簡単に管理できます。 - 全画面ローディング対応 Element PlusのElLoadingを活用し、グローバルなオーバーレイを迅速に実装し、視覚効果を向上させます。
- 柔軟で再利用可能 一度定義すれば、プロジェクト全体で便利に呼び出せるため、開発効率が大幅に向上します。
まとめ
useLoadingフックを使用することで、Axios通信時のローディング状態を優雅に管理できます。コードの冗長性を減らし、再利用性を高めるこのアプローチは、プロジェクトのコードベースを簡素化し、保守性を向上させます。
このソリューションがプロジェクトの役に立てば幸いです!