Front-End프로그래밍

[Vue3,ts,vit] axios 통신할때 스피너 로딩바 구현 후 통신끝나면 로딩바 감추기

Vue 3 + Vite 프로젝트에서 Axios를 사용할 때 전역 로딩바(Global Loading Bar)를 구현하는 일반적인 방식은 다음과 같다

Axios 통신 중에 화면 중앙에 회전 로딩 스피너를 보여주는 방식으로 구현한 예시이다.

구현 전략

  1. Axios Interceptor를 활용해 요청 시작 시 로딩 시작, 응답 완료 시 로딩 종료.
  2. Pinia 또는 Reactive State로 로딩 상태 관리.
  3. 컴포넌트에서 로딩 UI 표시.
  4. Axios 요청 중일 때 전체 화면을 덮는 회전 스피너 표시
  5. 요청이 끝나면 자동으로 사라짐

1. 로딩 상태 전역 관리 (Pinia 사용)

먼저 Pinia를 설치하지 않았다면 설치:

npm install pinia

stores/loading.ts 또는 stores/loading.ts 생성:

import { defineStore } from 'pinia'

export const useLoadingStore = defineStore('loading', {
  state: () => ({
    loading: false
  }),
  actions: {
    start() {
      this.loading = true
    },
    stop() {
      this.loading = false
    }
  }
})


2. Axios Interceptor 설정

plugins/axios.js 또는 utils/axios.js 파일 생성:

import axios from 'axios'
import { useLoadingStore } from '@/stores/loading'

const api = axios.create({
  baseURL: '/api'
})

api.interceptors.request.use(
  (config) => {
    const loading = useLoadingStore()
    loading.start()
    return config
  },
  (error) => {
    const loading = useLoadingStore()
    loading.stop()
    return Promise.reject(error)
  }
)

api.interceptors.response.use(
  (response) => {
    const loading = useLoadingStore()
    loading.stop()
    return response
  },
  (error) => {
    const loading = useLoadingStore()
    loading.stop()
    return Promise.reject(error)
  }
)

export default api


3. 메인 설정에 Pinia 추가

main.js 또는 main.ts:

import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'

const app = createApp(App)

app.use(createPinia())
app.mount('#app')


4. 로딩 바 컴포넌트 만들기 (src/components/LoadingBar.vue)

<template>
  <div v-if="loading" class="overlay">
    <div class="spinner"></div>
  </div>
</template>

<script setup>
import { computed } from 'vue'
import { useLoadingStore } from '@/stores/loading'

const loadingStore = useLoadingStore()
const loading = computed(() => loadingStore.loading)
</script>

<style scoped>
.overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(255, 255, 255, 0.6);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 10000;
}

.spinner {
  width: 60px;
  height: 60px;
  border: 8px solid #ccc;
  border-top: 8px solid #42b983;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
</style>


5. App.vue에서 로딩바 표시

src/App.vue

<template>
  <LoadingBar />
  <router-view />
</template>

<script setup>
import LoadingBar from '@/components/LoadingBar.vue'
</script>

6. 사용 예시 (컴포넌트에서 API 호출)

<template>
  <button @click="fetchData">데이터 가져오기</button>
</template>

<script setup>
import api from '@/utils/axios'

const fetchData = async () => {
  try {
    const res = await api.get('/test') // 백엔드 테스트용 엔드포인트
    console.log(res.data)
  } catch (err) {
    console.error('에러 발생:', err)
  }
}
</script>

테스트 팁

  • 네트워크 응답이 너무 빠르면 로딩바가 안 보일 수 있어요.
    → 테스트용으로 setTimeoutresponse interceptor에 넣으면 좋아요:
await new Promise(resolve => setTimeout(resolve, 1000)) // 응답 지연


요약

  • Pinia로 로딩 상태를 전역 관리.
  • Axios Interceptor로 자동으로 로딩 제어.
  • 컴포넌트로 로딩바 표시.
구성 요소설명
Pinia전역 로딩 상태 관리
Axios요청 전/후 로딩 상태 토글
LoadingSpinner.vue중앙 회전 스피너 컴포넌트
App.vue전역으로 로딩 UI 삽입

error: Content is protected !!