이번 포스트에서는 다양한 방식으로 경로를 매칭하는 방법에 대해 알아보자.
파라미터를 활용한 동적 라우팅
params와 query
가끔 동일한 컴포넌트를 주어진 경로의 패턴에 따라 동작시켜야 하는 경우가 있다. 예를 들어 사용자의 프로필을 표현하는데 /profile/hong , /profile/jang 형태로 불리는 경우이다.
당연히 이 과정에서 개인의 profile을 보여주는 component는 동일 하고 뒤에 있는 /profile/[사용자이름] 의 경로가 처리될 필요가 있다.
이를 위해 route에는 파라미터 라는 것을 사용하는데 : 을 이용해서 표현한다. 마치 스프링에서 path variable과 유사하다.
{
path: '/profile/:id',
component: DynamicPathView
}
이 경로를 호출할 때 /profile/hong , /profile/jang의 형태로 path를 작성해 주면 된다.
<RouterLink to="/profile/hong">동적 1</RouterLink> |
<RouterLink to="/profile/jang">동적 2</RouterLink> |
파라미터 외에 get 방식의 url을 구성하던 query string 도 전달할 수 있는데 이때는 그냥 ?와 &를 이용해서 path에 추가 하면 되고 route에 설정할 필요는 없다 . 이렇게 전달된 query는 Route의 fullPath를 구성한다.
<RouterLink to="/profile/hong">동적 1</RouterLink> |
<RouterLink to="/profile/jang">동적 2</RouterLink> |
<RouterLink to="/profile/lim?age=30&addr=seoul">동적 3</RouterLink> |
component에서의 활용
전달된 파라미터와 query는 component에서 Route를 통해 참조 가능 하다. (경로 이동 을 위해서는 Router 이고 개별 경로 는 Route 이다.) Route객체는 vue-router의 useRoute 함수를 이용 해서 얻을 수 있는데 params 속성에 전달된 파라미터들이 객체 형태로 등록된다. query 역시 Router의 query 속성에서 확인할 수 있다.
<template>
<div>
<h2>Params & Query</h2>
<ul>
<li>{{ route.params }}</li>
<li>{{ route.query }}</li>
</ul>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
</script>
component에서 확인하는 params와 query 속성의 값
params 변경에 반응하기
일반적으로 router를 통해서 component를 교체할 때는 [기존 component unmount] =>[신규 component create(setup)]의 라이프 사이클을 탄다. 하지만 dynamic routing의 경우는 component 가 교체되지 않고 재사용 된다. 즉 [기존 component update ] 라이프 사이클 훅만 반복된다.
값의 변경을 component에서 모니터링 하기 위해서 는 watch() 를 이용하거나 뒤에서 살펴볼 내비게이션 가드의 beforeRouteUpdate에서 처리 할 수 있다.
watch(
() => route.params.id, // getter를 이용하는 형태
(newParam, oldParam) => {
console.log('watch ', oldParam, '=>', newParam)
},
{ immediate: true }
)
다양한 경로 매칭
정규 표현식의 사용과 404 처리
지금까지 만들어본 경로(정적, 동적 router 포함)를 개발자 도구의 Routes 탭에서 살펴보면 매우 신기한 내용을 확인할 수 있다.(간혹 Routes가 보이지 않으면 캐시 비우기 및 강력 새로고침을 해보자.)
경로는 정규 표현식으로 처리된다.!
바로 모든 경로 는 사실 정규 표현식으로 처리된다 는 점이다. 지금은 주어진 경로가 그대로 정규 표현식에 매칭되지만 우리가 정규 표현식으로 경로를 작성하면 그것을 이용해서 정규표현식에 부합하는 여러 경로를 하나의 path에서 처리 할 수 있다.
경로를 정규 표현식으로 작성하려면 : 와 함께 함수 형태로 경로를 작성하고 파라미터로 정규 표현식 을 넘겨주면 된다.
다음의 표현은 .* 이므로 / 뒤에 어떠한 문자가 0개 이상 나오는 상황에 매핑될 수 있다.
{
path: '/:regexpath(.*)',
component: NotFoundView
},
vue-router는 평가되는 정규 표현식의 경로별로 점수(우선순위)를 갖는데 만약 요청 경로에 매핑되는 표현식이 여러가지인 경우는 높은 점수의 표현식을 갖는 route를 사용하게 된다.(일반적으로 와일드 카드를 사용하는 경우 점수가 낮다.)
Vue Router Path Parser
paths.esm.dev
위 표현식(.*)은 평가 점수가 20점으로 매우 낮은 편(만점은 80점)이어서 다른 표현식이 아무도 없다면 NotFoundView에 연결된다.
이전 버전의 router에서는 정규 표현식이 없었고 작성 순서가 앞서면 높은 우선순위를 가졌었다.
참고로 요청 경로는 route의 params로 전달되는데 route.params의 param 이름은 정규표현식 함수의 이름이 된다.
v-bind:to 활용
to 속성에서 위와 같은 처리를 하기 위해서는 단순 문자열이 아닌 객체 형태로 속성을 binding 하면 된다. 마치 router.push() 메서드에 객체를 넘겨주는 것처럼 :to를 설정해주기만 하면 된다.
<RouterLink :to="{path:'/'}">기본</RouterLink> |
<RouterLink :to="{path:'/profile/hong'}">동적 1(hong)</RouterLink> |
<RouterLink :to="{name:'DynamicProfile', params:{id:'jang'} , query:{age:20}}">동적 2(jang)</RouterLink> |
<RouterLink :to="{path:'/profile/lim', query:{age:30}}">동적 3(lim)</RouterLink> |
<RouterLink :to="{path:'/some'}">404처리</RouterLink>
이렇게 보면 name을 이용한 경로 설정이 훨씬 길어 보이지만 path가 좀 더 복잡해지면 훨씬 간단하게 처리할 수 있다. 또한 경로의 변경이 발생하는 경우 path를 이용했다면 사용된 모든 컴포넌트에서 변경해줘야 하지만 name을 사용하면 단지 router에서만 변경처리하면 간단해진다.
프로그래밍 방식 활용
프로그래밍 방식으로 params와 query를 전달하는 방법을 알아보자.
먼저 path기반으로 처리 할 때는 params를 path에 연결해서 전달 하고 쿼리만 별도로 전달 한다. 하지만 name 속성을 사용할 때에는 params와 query를 모두 별도로 전달 한다.
<script setup>
const router = useRouter();
// path 기반은 path와 query만 사용(params는 path에 포함시킬 것)
const pathBase = (path, query)=>{
router.push({path, query})
}
// name 기반은 name, params, query 모두 사용 가능
const nameBase = (name, params, query)=>{
router.push({name, params, query});
}
</script>
<button @click="pathBase('/profile/hong')">path</button>
<button @click="pathBase('/profile/lim', {age:30})">path + query</button>
<button @click="nameBase('DynamicProfile', {id:'jang'}, {age:20})">name + params + query</button>