log
Swift Code Chronicles

How to Elegantly Manage Loading States in a Vue Project

Published on December 9, 2024
Updated on January 30, 2025
21 min read
Vue

When handling front-end and back-end communication, displaying a loading state is a common way to inform users about the ongoing process. However, in a project with multiple Axios requests, manually adding loading logic before and after each request can lead to redundant and hard-to-maintain code.

To address this issue, I designed a reusable Loading Hook component based on Element Plus and Axios. This solution simplifies the codebase and enhances reusability. Below, I’ll explain the implementation and usage in detail.


Implementation

The Hook centralizes the loading logic and offers the following features:

  • Manage a general loading state.
  • Handle multiple asynchronous requests simultaneously.
  • Support fullscreen loading effects, ideal for global overlays.

Hook Implementation Code

// hooks/use-loading.hook.ts
import { ref } from 'vue'
import { ElLoading } from 'element-plus'

type Options = {
  /** Initial value */
  initialValue?: boolean
}

export function useLoading({ initialValue = false }: Options = {}) {
  /** Loading state */
  const isLoading = ref(initialValue)

  /**
   * Start loading
   */
  const startLoading = () => {
    isLoading.value = true
  }

  /**
   * Stop loading
   */
  const stopLoading = () => {
    isLoading.value = false
  }

  /**
   * Handle multiple asynchronous requests
   * @param promises List of async requests
   * @returns Results of all async requests
   */
  const withLoading = async <T>(promises: Array<() => Promise<T>>) => {
    startLoading()
    try {
      return await Promise.all(promises.map((promise) => promise()))
    } finally {
      stopLoading()
    }
  }

  /**
   * Handle multiple asynchronous requests with fullscreen loading
   * @param promises List of async requests
   * @returns Results of all async requests
   */
  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 }
}

Usage

Here’s a complete example demonstrating how to use the useLoading Hook to manage loading states in a Vue component.

<template>
  <div class="wrapper">
    <button @click="clickHandler">Fetch Japanese Holidays</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'

// Using the useLoading Hook
const { withFullscreenLoading } = useLoading()
const holidayList = ref<any>({})

// Encapsulating the request logic
const requestJapaneseHoliday = async () => {
  const resp = await axios.get('https://holidays-jp.github.io/api/v1/date.json')
  return resp.data
}

// Button click handler
const clickHandler = async () => {
  const [data] = await withFullscreenLoading([requestJapaneseHoliday])
  holidayList.value = data
}
</script>

Advantages

  1. Decoupled Logic. By extracting the loading state management into a Hook, you avoid repetitive start/stop logic in every request, resulting in cleaner and more concise code.
  2. Supports Concurrent Requests. Whether handling a single request or multiple asynchronous requests, withLoadingandwithFullscreenLoadingmake it easy to manage them.
  3. Fullscreen Loading Support. Leveraging Element Plus’s ElLoading component, you can implement a global overlay quickly, improving the visual experience.
  4. Reusable and Flexible. Once defined, the Hook can be reused throughout the project, significantly improving development efficiency.

Conclusion

By encapsulating the loading state management in the useLoading Hook, you can elegantly handle Axios communications with reduced code redundancy and enhanced reusability. This approach simplifies your project’s codebase while improving maintainability.

I hope this solution is helpful for your project!

About

A personal blog sharing technical insights, experiences and thoughts

Quick Links

Contact

  • Email: hushukang_blog@proton.me
  • GitHub

© 2025 Swift Code Chronicles. All rights reserved