라우팅 — Vue Router 시작하기

라우팅 — Vue Router 시작하기

단일 페이지 애플리케이션(SPA)에서는 브라우저 URL을 화면에 보이는 콘텐츠와 연결해 줘야 해요. Vue Router는 Vue 공식 클라이언트 사이드 라우팅 솔루션이고, 사용자가 앱을 둘러다니며 URL이 바뀌어도 서버에서 페이지를 다시 불러오지 않게 해 줍니다. Vue의 컴포넌트 시스템 위에 만들어져서, 각 URL 경로에 어떤 컴포넌트를 보여줄지 라우트(routes)로 설정하면 되지요.

출처: Vue Router 공식 문서 - Getting Started

예시로 보는 핵심 개념

먼저 루트 컴포넌트 App.vue를 살펴볼게요.

App.vue

<template>
  <h1>Hello App!</h1>
  <p><strong>Current route path:</strong> {{ $route.fullPath }}</p>
  <nav>
    <RouterLink to="/">Go to Home</RouterLink>
    <RouterLink to="/about">Go to About</RouterLink>
  </nav>
  <main>
    <RouterView />
  </main>
</template>

이 템플릿은 Vue Router가 제공하는 RouterLinkRouterView 두 컴포넌트를 쓰고 있어요.

일반 <a> 태그 대신 커스텀 컴포넌트 RouterLink로 링크를 만듭니다. 그러면 페이지를 다시 불러오지 않고도 Vue Router가 URL을 바꾸고, URL 생성·인코딩 등 여러 기능을 처리할 수 있어요. RouterView는 현재 URL 경로에 대응하는 라우트 컴포넌트를 어디에 렌더링할지 Vue Router에게 알려줍니다. 꼭 App.vue에 있을 필요는 없고, 레이아웃에 맞춰 어디든 둘 수 있지만 반드시 어딘가에 포함돼 있어야 해요. 없다면 Vue Router는 아무것도 렌더링하지 않습니다.

예시는 템플릿에서 {{ $route.fullPath }}로 현재 라우트를 나타내는 객체에 접근하기도 해요. $route를 쓰면 현재 라우트를 표현하는 객체에 접근할 수 있습니다.

라우터 인스턴스 만들기

라우터 인스턴스는 createRouter() 함수를 호출해 만듭니다.

import { createMemoryHistory, createRouter } from 'vue-router'

import HomeView from './HomeView.vue'
import AboutView from './AboutView.vue'

const routes = [
  { path: '/', component: HomeView },
  { path: '/about', component: AboutView },
]

export const router = createRouter({
  history: createMemoryHistory(),
  routes,
})

routes 옵션은 URL 경로를 컴포넌트에 매핑하는 라우트 자체를 정의해요. component 옵션으로 지정한 컴포넌트가 앞서 App.vue<RouterView>에 렌더링되는 컴포넌트입니다. 이런 라우트 컴포넌트를 _views_라고 부르기도 하지만, 그냥 평범한 Vue 컴포넌트일 뿐이에요. 지금은 pathcomponent만 알면 충분하고, 라우트가 지원하는 다른 옵션들은 이어지는 문서에서 만나게 됩니다.

history 옵션은 라우트를 URL에, URL을 라우트에 매핑하는 방식을 제어합니다. 예시에서는 브라우저 URL을 무시하고 자체 내부 URL을 쓰는 createMemoryHistory()를 썼어요. Playground에서는 잘 맞지만 실제 앱에선 보통 createWebHistory()createWebHashHistory()를 쓰게 됩니다.

라우터 플러그인 등록하기

라우터 인스턴스를 만들고 나면 앱에 플러그인으로 등록해야 해요. createApp()이 반환한 앱에 use()를 호출하면 됩니다.

createApp(App).use(router).mount('#app')

또는 이렇게 나눠서 쓸 수도 있어요.

const app = createApp(App)
app.use(router)
app.mount('#app')

대부분의 Vue 플러그인처럼 use() 호출은 mount()보다 먼저 해야 해요. 이 플러그인이 하는 일을 궁금해한다면, 대략 다음과 같습니다.

  1. RouterViewRouterLink 컴포넌트를 전역 등록
  2. 전역 $router$route 속성 추가
  3. useRouter()useRoute() 컴포저블 활성화
  4. 라우터가 초기 라우트를 해석하도록 트리거

라우터와 현재 라우트에 접근하기

라우터 인스턴스를 ES 모듈로 export 하면 필요한 곳에서 직접 import 해 쓸 수 있어요. 어떤 상황에서 이게 가장 좋을 때도 있지만, 컴포넌트 안이라면 다른 방법이 있습니다.

컴포넌트 템플릿에서는 라우터 인스턴스가 $router로 노출돼요. 아까 본 $route와 비슷하지만 끝에 r이 하나 더 붙는다는 걸 기억하세요. Options API를 쓴다면 JavaScript 코드에서 this.$routerthis.$route로 같은 두 속성에 접근할 수 있습니다.

export default {
  methods: {
    goToAbout() {
      this.$router.push('/about')
    },
  },
}

이 메서드는 프로그래매틱 내비게이션에 쓰는 push()를 호출해요. Composition API에서는 this로 컴포넌트 인스턴스에 접근할 수 없어서, Vue Router는 대신 쓸 컴포저블을 제공합니다.

<script setup>
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'

const router = useRouter()
const route = useRoute()

const search = computed({
  get() {
    return route.query.search ?? ''
  },
  set(search) {
    router.replace({ query: { search } })
  },
})
</script>

지금 당장 이 코드 전체를 이해할 필요는 없어요. 핵심은 라우터 인스턴스와 현재 라우트에 각각 useRouter()useRoute() 컴포저블로 접근한다는 점입니다.

다음 단계

Vite를 쓰는 완전한 예시가 필요하다면 create-vue 스캐폴딩 도구를 써 보세요. 예시 프로젝트에 Vue Router를 포함하는 옵션이 있습니다.

npm create vue@latest
yarn create vue
pnpm create vue

create-vue가 만든 예시 프로젝트는 여기서 본 것과 비슷한 기능을 써요. 이어지는 문서에서 소개할 기능들을 탐색하기 좋은 출발점이 될 거예요.

이 문서의 관례

단일 파일 컴포넌트

Vue Router는 보통 Vite 같은 번들러와 SFC(.vue 파일)를 쓰는 앱에서 가장 많이 사용돼요. 대부분의 예시는 그 스타일로 작성되지만, Vue Router 자체가 빌드 도구나 SFC를 요구하진 않습니다. 예를 들어 Vue와 Vue Router의 글로벌 빌드를 쓰면 라이브러리가 import가 아니라 전역 객체로 노출돼요.

const { createApp } = Vue
const { createRouter, createWebHistory } = VueRouter

컴포넌트 API 스타일

Vue Router는 Composition API와 Options API를 모두 지원하고, 그에 맞춰 두 스타일로 예시를 보여줍니다. Composition API 예시는 보통 명시적인 setup 함수보다 <script setup>을 써요.

routerroute

문서 전반에서 라우터 인스턴스를 router라고 부를게요. 이건 createRouter()가 반환한 객체예요. Composition API 컴포넌트에서는 useRouter()로, Options API에서는 this.$router로 접근할 수 있습니다. 마찬가지로 현재 라우트는 route로 부르고, 컴포넌트에서 useRoute() 또는 this.$route로 접근해요.

RouterViewRouterLink는 둘 다 전역 등록되어 있어 컴포넌트 템플릿에서 쓰기 전에 import 할 필요가 없어요. 원한다면 import { RouterLink } from 'vue-router'처럼 로컬로 import 해도 됩니다. 템플릿 안의 컴포넌트 이름은 PascalCase든 kebab-case든 Vue 템플릿 컴파일러가 둘 다 지원하니, 프로젝트의 관례를 따르면 돼요. 다만 in-DOM 템플릿을 쓴다면 컴포넌트 이름을 kebab-case로 쓰고 자체 닫힘 태그를 쓸 수 없으므로, <RouterView /> 대신 <router-view></router-view>처럼 써야 해요.

더 알아보기