Vue Router

Vue Router는 SPA and CSR 위에서 동작하는 client-side router로, browser URL을 Vue.js component tree에 mapping한다. Route map, dynamic/named route, programmatic navigation, nested route, route props, lazy loading, navigation guard라는 하위 메커니즘을 가지며, 이 페이지가 답하는 질문은 URL state와 rendered component hierarchy를 어떻게 일치시키는가다.

Route 매칭과 Navigation 흐름

flowchart LR
  URL[Browser URL] --> Match[Route records match]
  Match --> Guard[Guard pipeline]
  Guard -->|approved| Load[Load route component]
  Load --> View[RouterView renders]
  Guard -->|redirected or cancelled| URL

Router가 URL을 application state의 외부 표현으로 다루는 이유

Router는 단순 menu 전환 도구가 아니라 URL을 application state의 외부 표현으로 유지하는 경계라고 볼 수 있다. URL parameter는 share/bookmark/back-forward navigation이 필요한 state에 적합하고, component local state나 global store를 모두 대체하지는 않는다. Route name은 path structure가 바뀌어도 caller가 의도 중심 navigation을 유지하게 해준다.

Guard는 인증·권한·이탈 확인 같은 navigation policy에 사용하되 data fetching 전체를 하나의 global guard에 몰지 않는 편이 낫다 — 모든 data loading과 authorization logic을 global guard 하나에 집중하는 것은 흔한 실패 모드다.

주요 구성 요소

요소 역할 주의점
routes URL pattern과 component를 mapping Route order와 dynamic segment 범위를 확인한다.
RouterLink Client navigation link 생성 단순 click handler보다 link semantics를 보존한다.
RouterView Matched component outlet Nested route마다 필요한 outlet을 둔다.
useRoute() 현재 route state 읽기 Route object 전체보다 필요한 param/query를 관찰한다.
useRouter() Programmatic navigation 실행 User-facing link는 RouterLink를 우선한다.

Nested route와 route props

Lazy loading

const routes = [
  {
    path: '/about',
    component: () => import('./views/AboutView.vue'),
  },
]

Source p.52의 흐름을 재사용 가능한 순서로 단순화하면 다음과 같다.[1:6]

  1. Navigation이 trigger된다.
  2. Leaving component guard와 global beforeEach가 실행된다.
  3. Reused component update guard와 route beforeEnter가 실행된다.
  4. Async route component를 resolve하고 entering component guard를 실행한다.
  5. Global beforeResolve 후 navigation을 confirm한다.
  6. Global afterEach와 DOM update가 이어진다.

경계

예시

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

const routes = [
  {
    path: '/users/:id',
    name: 'user',
    component: () => import('./views/UserView.vue'),
    props: true,
    children: [
      { path: 'settings', name: 'user-settings', component: () => import('./views/UserSettings.vue') },
    ],
  },
]

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

router.beforeEach((to) => {
  if (to.meta.requiresAuth && !isAuthenticated()) {
    return { name: 'login', query: { redirect: to.fullPath } }
  }
})

관련

출처

테스트 질문


  1. 05.Vuejs-Router.pdf — RouterLink/RouterView, dynamic/named route, nested route, route props, lazy loading, navigation guard flow(p.52) ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  2. vue-router-navigation-guards.md — global/per-route/in-component guard, beforeEach에서 false/route location return의 의미, next callback style; "Global before guards are called in creation order"(L27), "you must call next exactly once in any given pass through a navigation guard"(L68), "The Full Navigation Resolution Flow"(L287-299) ↩︎ ↩︎ ↩︎ ↩︎