Vue Router가 무엇인지, 어떻게 활용하는지 궁금하다면?
2025.11.19 - [Web/Vue] - Vue Router 기초 (Vue 2 + Vue Router 3)
Vue Router 기초 (Vue 2 + Vue Router 3)
1. SPA에서 라우터가 필요한 이유Vue로 간단한 컴포넌트까지만 만들 때는 하나의 페이지에서만 작업해도 충분하지만,실제 서비스에서는 다음과 같은 화면이 필요해집니다./login: 로그인 페이지/use
sproutinghye.tistory.com
1. Axios
라우팅으로 화면 구조를 만들었다면, 이제 서버에서 데이터를 가져와 화면에 뿌려야 합니다.
Vue 진영에서 가장 많이 사용되는 HTTP 클라이언트가 Axios입니다.
Axios는
- 브라우저와 Node.js 양쪽에서 사용 가능
- Promise 기반 비동기 처리 지원 (async / await)
- 요청/응답 인터셉터, 공통 헤더, 데이터 변환 등 다양한 기능 제공
하는 HTTP 클라이언트 라이브러리입니다.
Vue 공식 문서에서도 API 데이터를 가져오는 예제에서 Axios를 사용해 설명할 정도로
Axios는 다른 라이브러리보다 자주 등장해요.
- 설치
npm install axios
# 또는
yarn add axios
npm이나 yarn 말고도, CDN으로도 바로 사용할 수 있습니다.
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
- GET 요청 패턴
가장 많이 쓰는 패턴은 컴포넌트가 만들어질 때(created/mounted) API를 호출해서 데이터를 채우는 것입니다.
import axios from 'axios'
export default {
data() {
return {
posts: [],
loading: false,
error: null
}
},
created() {
this.fetchPosts()
},
methods: {
async fetchPosts() {
this.loading = true
this.error = null
try {
const res = await axios.get('https://jsonplaceholder.typicode.com/posts')
this.posts = res.data
} catch (e) {
this.error = '데이터를 불러오는 중 오류가 발생했습니다'
} finally {
this.loading = false
}
}
}
}
실무에서도 거의 이런 구조를 그대로 씁니다.
- loading: API 호출 중인지 여부
- error: 에러 메시지 저장
- res.data: 서버에서 받은 실제 데이터
이 세 가지를 상태로 관리하면 템플릿에서 로딩 스피너, 에러 메시지, 정상 데이터를 상황에 맞게 보여줄 수 있어요.
- POST 요청 패턴
폼 데이터를 서버에 전송할 때는 axios.post를 사용합니다.
async submitForm() {
this.loading = true
this.error = null
try {
const payload = {
title: this.title,
body: this.body,
userId: 1
}
const res = await axios.post(
'https://jsonplaceholder.typicode.com/posts',
payload
)
console.log('생성된 데이터:', res.data)
} catch (e) {
this.error = '저장 중 문제가 발생했습니다'
} finally {
this.loading = false
}
}
기본 형식은 axios.post(url, data, config)이고,
config에는 헤더나 토큰 등을 넣을 수 있습니다.
- Axios 인스턴스로 공통 설정 빼두기
규모가 있는 프로젝트에서는 매번 axios.get('https://api.xxx.com/...')를 쓰기보다,
기본 URL과 공통 헤더를 가진 Axios 인스턴스를 만들어두고 import해서 쓰는 방식이 편합니다.
// api.js
import axios from 'axios'
const api = axios.create({
baseURL: 'https://jsonplaceholder.typicode.com',
timeout: 5000
})
// 요청 인터셉터, 응답 인터셉터도 여기서 설정 가능
// api.interceptors.request.use(...)
// api.interceptors.response.use(...)
export default api
사용 예는 아래와 같습니다.
import api from '@/api'
export default {
async fetchPosts() {
const res = await api.get('/posts')
this.posts = res.data
}
}
이렇게 설정해두면 베이스 URL, 공통 토큰 설정, 에러 처리 로직을 한 곳에서 관리할 수 있습니다.
2. 라우터 + Axios 실전 예제
이제 Vue Router와 Axios를 묶어서 실제 서비스에서 거의 그대로 쓰는 패턴인
목록 페이지 + 상세 페이지 구조를 구현해보겠습니다.
- /posts: 게시글 목록 페이지
- /posts/:id: 게시글 상세 페이지
라는 구조를 예로 들겠습니다.
1️⃣ 라우트 설정
// router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import PostList from '@/views/PostList.vue'
import PostDetail from '@/views/PostDetail.vue'
Vue.use(VueRouter)
const routes = [
{ path: '/posts', component: PostList },
{ path: '/posts/:id', component: PostDetail }
]
const router = new VueRouter({
mode: 'history',
routes
})
export default router
- /posts -> PostList 컴포넌트
- /posts/:id -> PostDetail 컴포넌트
- :id는 동적 파라미터로, this.$route.params.id로 읽을 수 있습니다.
2️⃣ 목록 페이지: 라우터 + Axios
<template>
<div>
<h2>게시글 목록</h2>
<p v-if="loading">로딩 중...</p>
<p v-else-if="error">{{ error }}</p>
<ul v-else>
<li v-for="post in posts" :key="post.id">
<!-- 상세 페이지로 이동 -->
<router-link :to="`/posts/${post.id}`">
{{ post.title }}
</router-link>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
posts: [],
loading: false,
error: null
}
},
create() {
this.fetchPosts()
},
methods: {
async fetchPosts() {
this.loading = true
this.error = null
try {
const res = await axios.get(
'https://jsonplaceholder.typicode.com/posts'
)
this.posts = res.data.slice(0, 10)
} catch (e) {
this.error = '게시글을 불러오지 못했습니다.'
} finally {
this.loading = false
}
}
}
}
</script>
핵심 포인트는 세 가지입니다.
- create() 훅에서 fetchPosts() 호출
- Axios로 API 데이터를 받아 posts 배열에 세팅
- v-for로 목록 렌더링 + 각 항목을 router-link로 상세 페이지와 연결
3️⃣ 상세 페이지: 동적 라우트 + Axios
<template>
<div>
<p>
<router-link to="/posts">← 목록으로</router-link>
</p>
<div v-if="loading">로딩 중...</div>
<div v-else-if="error">{{ error }}</div>
<div v-else-if="post">
<h2>{{ post.tile }}</h2>
<p>{{ post.body }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
post: null,
loading: false,
error: null
}
},
create() {
this.fetchPost()
},
watch: {
'$route.params.id': 'fetchPost' // id가 바뀌면 다시 게시글 불러오기
},
methods: {
async fetchPost() {
this.loading = true
this.error = null
const id = this.$route.params.id
try {
const res = await.get(
`https://jsonplaceholder.typicode.com/posts/${id}`
)
} catch (e) {
this.error = '게시글 정보를 가져오지 못했습니다.'
} finally {
this.loading = false
}
}
}
}
</script>
- this.$route.params.id로 현재 URL의 :id 값을 참조
- 동적 라우트에서 같은 컴포넌트가 재사용될 때를 대비해
watch: { '$route.params.id': 'fetchPost' }로 id 변화를 감시하고 재요청 - 로딩/에러/정상 데이터를 템플릿에서 조건부 렌더링
실제 서비스에서 게시글, 공지사항, 상품, 유저, 주문 등 목록에서 상세 페이지로
가는 구조를 가진 거의 모든 도메인이 같은 방식으로 구현됩니다.
- 목록 페이지에서
- Axios로 리스트 데이터를 불러오고
- router-link로 각 상세 페이지와 연결
- 상세 페이지에서
- URL 파라미터($route.param.id)를 사용해서
- Axios로 단일 리소스를 다시 요청
이 패턴만 익어도 CRUD 뷰들을 금방 만들어낼 수 있어요.
정리
- Axios 기본 사용법
- axios.get, axios.post
- loading, error, data 상태 패턴
- Axios 인스턴스로 baseURL, 공통 설정 분리
- Vue Router + Axios 실전 패턴
- /posts 목록 페이지에서 리스트 데이터 렌더링
- /posts/:id 상세 페이지에서 URL 파라미터로 단일 데이터 요청
- router-link, $route.params, watch를 활용한 동적 라우팅
출처
Vue Router 공식 문서 - 동적 라우트 매칭과 파라미터
'Framework > Vue' 카테고리의 다른 글
| Vuex를 이용한 Vue 전역 상태 관리 예제 (0) | 2025.11.20 |
|---|---|
| Vuex 기초: Vue 전역 상태 관리 (state, getters, mutations, actions, modules) (1) | 2025.11.20 |
| Vue Router 기초 (Vue 2 + Vue Router 3) (1) | 2025.11.19 |
| Vue.js SFC, props, emit으로 부모-자식 데이터 흐름 잡기 (0) | 2025.11.19 |
| Vue2 Options API : data, methods, computed, watch (0) | 2025.11.19 |