네비게이션 가드를 통해 잘못된 페이지 이동 시 리다이렉트/취소하여 Nativation을 보호하기
웹페이지 내에서 페이지 간의 이동을 할 때, URL에 따라서 유효하지 않은 URL인 경우가 있을 수 있다. 몇 가지 상황에 따라 예시를 분류하자면,
먼저 동적 라우트 매칭을 통해 컴포넌트로 이동하는 경우, 상황에 따라 올바르지 않은 자료형 or 범위의 parameter를 임의로 입력할 수도 있다. 예를 들어 https://example.com/history/<year> 라는 주소를 생각해보자. parameter로 연도를 받아서 그 값에 따라 데이터를 불러오는 화면이라면, parameter로 문자열이 들어온다면(ex. https://example.com/history/hello ) 제대로 된 데이터를 불러올 수 없을 것이다.
흔한 경우는 아니지만, 만약 페이지 이동 시에 이동 전 화면에 따라 다음 화면에서 표시하는 내용이 달라질 수도 있다.
그 외에도 특정 화면에 대한 접근 권한을 체크할 때에도 많이 사용한다고 한다.
위와 같이 내가 공부한 바로는 크게 3가지 정도의 경우로 나눌 수 있을 것 같다.
네비게이션 가드의 종류는 크게 3가지로 나눌 수 있다. 각각에 대해서 조금 더 자세히 알아보자. 이때 각각의 예시는 [1]Vue Router 공식 문서를 참고하였다.
전역 가드는 '전역(Global)'이라는 단어가 개발 분야에서 일반적으로 사용되는 것처럼 모든 네비게이션에 대해 발생되는 네비게이션 가드이다. 즉, 페이지 이동이 발생할 때마다 실행되는 코드라고 보면 될 것 같다.
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
위에서처럼 beforeEach 라는 메서드를 통해서 실행되며, 이 메서드는 3개의 parameter가 있다. to 의 경우 현재의 라우트, 즉 네비게이션을 통해 이동할 객체를 의미한다. from 의 경우는 현재 라우트로 오기 전 라우트를 의미한다. from 과 to 모두 자료형은 라우트 객체이다. next() 는 'hook을 해결하기 위해' 반드시 호출되어야 한다. 'hook을 해결한다'는 표현은 조금 추상적으로 이해가 된다. 대략적으로 이해한 바에 따르면, 유저의 사용 흐름 상에서 네비게이션 자체는 일시정지, next() 는 다시 재생하기 정도의 기능으로 이해하면 되지 않을까 싶다. next() 를 parameter 없이 사용한다면, 이동하려고 했던 라우트로 이동하지만, 만약 인자를 전달한다면 (ex. next('/') , next({ path: '/' })) 해당 라우트로 리다이렉트 한다. 이 경우 새로운 네비게이션이 시작된다고 한다. 그 외에도 next(false) 와 같이 인자로 false 값을 전달하면 from 의 라우트로 다시 이동하게 된다. 아마 접근 권한 등을 확인할 때 사용하지 않을까 싶다(?)
전역 가드와 다르게 특정 라우트 객체에 대해서만 네비게이션 가드를 설정할 수 있다. 이 경우 beforeEnter 를 사용한다. 사용 방법의 경우 전역 가드와 동일하다.
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
라우트 별 가드와 유사하면서도 조금씩 다르다. beforeRouteEnter 나 beforeRouteLeave 를 컴포넌트 안에 직접 정의하여 네비게이션 가드를 사용할 수 있다.
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 이 컴포넌트를 렌더링하는 라우트 앞에 호출됩니다.
// 이 가드가 호출 될 때 아직 생성되지 않았기 때문에
// `this` 컴포넌트 인스턴스에 접근 할 수 없습니다!
},
beforeRouteLeave (to, from, next) {
// 이 컴포넌트를 렌더링하는 라우트가 이전으로 네비게이션 될 때 호출됩니다.
// `this` 컴포넌트 인스턴스에 접근 할 수 있습니다.
}
}
하지만 beforeRouteEnter 의 경우 컴포넌트 생성 이전이기 때문에 this 에 접근을 할 수는 없다. 이 경우, next() 함수에서의 콜백을 통해 인스턴스에 접근할 수 있다.
beforeRouteEnter (to, from, next) {
next(vm => {
// `vm`을 통한 컴포넌트 인스턴스 접근
})
}
반대로 이름과 라이프 사이클을 생각하면 당연하지만, beforeRouteLeave 에서는 this 에 직접 접근할 수 있다. 주로 사용자가 저장하지 않은 편집 내용을 두고 실수로 페이지를 이동하는 것을 방지하는데 사용된다고 한다.
동적 라우트 매칭에서 parameter만 변경되는 경우, 컴포넌트의 라이프 사이클 훅이 호출되지 않는다. 따라서 네비게이션 가드 중 하나인 beforerouteUpdate 를 사용하면 새로운 훅을 만들 수 있다.
const User = {
template: '...',
beforeRouteUpdate (to, from, next) {
// react to route changes...
// don't forget to call next()
}
}