네비게이션 가드를 통해 잘못된 페이지 이동 시 리다이렉트/취소하여 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()
}
}