Skip to content

내비게이션 결과 기다리기 ​

router-link를 사용할 때 Vue Router는 내비게이션을 트리거하기 위해 router.push를 호출합니다. 대부분의 링크는 사용자를 새 페이지로 이동시키는 것이 기대되는 동작이지만, 사용자가 같은 페이지에 머무르게 되는 몇 가지 상황이 있습니다:

  • 사용자가 이미 이동하려는 페이지에 있는 경우
  • 내비게이션 가드가 return false를 실행해 내비게이션을 중단하는 경우
  • 이전 내비게이션이 끝나기 전에 새 내비게이션이 시작되는 경우
  • 내비게이션 가드가 새 location을 반환해 다른 곳으로 리다이렉트하는 경우(예: return '/login')
  • 내비게이션 가드가 Error를 throw하는 경우

내비게이션이 끝난 뒤 무언가를 하고 싶다면 router.push 호출 뒤에 기다릴 방법이 필요합니다. 예를 들어 여러 페이지로 이동할 수 있는 모바일 메뉴가 있고, 새 페이지로 이동한 뒤에만 메뉴를 숨기고 싶다면 다음과 같이 하고 싶을 수 있습니다:

js
router.push('/my-profile')
this.isMenuOpen = false

하지만 이렇게 하면 내비게이션이 비동기 이기 때문에 메뉴가 즉시 닫혀 버립니다. 따라서 router.push가 반환한 Promise를 await해야 합니다:

js
await router.push('/my-profile')
this.isMenuOpen = false

이제 내비게이션이 끝나면 메뉴가 닫히지만, 내비게이션이 막혔을 때도 닫히게 됩니다. 실제로 페이지가 바뀌었는지 여부를 감지할 방법이 필요합니다.

내비게이션 실패 감지하기 ​

내비게이션이 막혀 사용자가 같은 페이지에 머무르게 되면, router.push가 반환한 Promise의 resolve 값은 Navigation Failure 가 됩니다. 그렇지 않으면 falsy 값(보통 undefined)이 됩니다. 이를 통해 실제로 현재 위치에서 다른 페이지로 이동했는지 아닌지를 구분할 수 있습니다:

js
const navigationResult = await router.push('/my-profile')

if (navigationResult) {
  // 내비게이션이 방지됨
} else {
  // 내비게이션 성공(리다이렉트된 경우도 포함)
  this.isMenuOpen = false
}

Navigation Failure 는 어떤 내비게이션이 왜 막혔는지 알 수 있도록 몇 가지 추가 속성을 가진 Error 인스턴스입니다. 내비게이션 결과의 성격을 확인하려면 isNavigationFailure 함수를 사용하세요:

js
import { NavigationFailureType, isNavigationFailure } from 'vue-router'

// 저장하지 않은 채 기사 편집 페이지를 떠나려는 경우
const failure = await router.push('/articles/2')

if (isNavigationFailure(failure, NavigationFailureType.aborted)) {
  // 사용자에게 작은 알림을 표시합니다
  showToast('You have unsaved changes, discard and leave anyway?')
}

TIP

두 번째 매개변수(isNavigationFailure(failure))를 생략하면, failure가 Navigation Failure 인지만 확인합니다.

router.afterEach() 내비게이션 가드를 사용하면 전역 내비게이션 실패를 전역적으로 감지할 수 있습니다:

ts
router.afterEach((to, from, failure) => {
  if (failure) {
    sendToAnalytics(to, from, failure)
  }
})

내비게이션 실패 구분하기 ​

처음에 말했듯이 내비게이션을 중단시키는 상황은 여러 가지이며, 각각 서로 다른 Navigation Failure 로 이어집니다. 이들은 isNavigationFailure와 NavigationFailureType을 사용해 구분할 수 있습니다. 유형은 세 가지입니다:

  • aborted: 내비게이션 가드 안에서 false가 반환되어 내비게이션이 중단됨
  • cancelled: 현재 내비게이션이 끝나기 전에 새 내비게이션이 발생함. 예: 내비게이션 가드 안에서 기다리는 동안 router.push가 호출됨
  • duplicated: 이미 대상 location에 있기 때문에 내비게이션이 방지됨

모든 내비게이션 실패는 현재 location과 실패한 내비게이션의 대상 location을 나타내는 to와 from 속성을 노출합니다:

js
// 관리자 페이지에 접근하려는 경우
router.push('/admin').then(failure => {
  if (isNavigationFailure(failure, NavigationFailureType.aborted)) {
    failure.to.path // '/admin'
    failure.from.path // '/'
  }
})

모든 경우에 to와 from은 정규화된 라우트 location입니다.

리다이렉트 감지하기 ​

내비게이션 가드 안에서 새 location을 반환하면, 진행 중인 내비게이션을 덮어쓰는 새 내비게이션이 트리거됩니다. 다른 반환값과 달리 리다이렉트는 내비게이션을 막는 것이 아니라 새로운 내비게이션을 생성합니다. 따라서 확인 방식도 다르며, Route Location의 redirectedFrom 속성을 읽어 확인합니다:

js
await router.push('/my-profile')
if (router.currentRoute.value.redirectedFrom) {
  // redirectedFrom은 내비게이션 가드의 to와 from처럼 resolve된 라우트 location입니다
}

모두를 위한 문서 한글화