Skip to content

Vue Router와 Composition API

Vue의 Composition API 도입은 새로운 가능성을 열었지만, Vue Router의 잠재력을 온전히 활용하려면 this 접근과 컴포넌트 내부 내비게이션 가드를 대체하는 몇 가지 새로운 함수를 사용해야 합니다.

setup 안에서 라우터와 현재 라우트에 접근하기

setup 안에서는 this에 접근할 수 없으므로 this.$routerthis.$route에 직접 접근할 수 없습니다. 대신 useRouteruseRoute composable을 사용합니다:

vue
<script setup>
import { useRouter, useRoute } from 'vue-router'

const router = useRouter()
const route = useRoute()

function pushWithQuery(query) {
  router.push({
    name: 'search',
    query: {
      ...route.query,
      ...query,
    },
  })
}
</script>

route 객체는 반응형 객체입니다. 대부분의 시나리오에서는 전체 route 객체를 watch하지 않는 것이 좋습니다. 대신 변경될 것으로 예상하는 속성만 직접 watch할 수 있습니다:

vue
<script setup>
import { useRoute } from 'vue-router'
import { ref, watch } from 'vue'

const route = useRoute()
const userData = ref()

// params가 바뀌면 사용자 정보를 가져옵니다
watch(
  () => route.params.id,
  async newId => {
    userData.value = await fetchUser(newId)
  }
)
</script>

템플릿에서는 여전히 $router$route에 접근할 수 있으므로, 템플릿에서만 이 객체들이 필요하다면 useRouteruseRoute를 사용할 필요는 없습니다.

Vue Router는 update 가드와 leave 가드를 Composition API 함수로 제공합니다:

vue
<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
import { ref } from 'vue'

// beforeRouteLeave 옵션과 같지만 `this`에는 접근할 수 없습니다
onBeforeRouteLeave((to, from) => {
  const answer = window.confirm(
    'Do you really want to leave? you have unsaved changes!'
  )
  // 내비게이션을 취소하고 같은 페이지에 머뭅니다
  if (!answer) return false
})

const userData = ref()

// beforeRouteUpdate 옵션과 같지만 `this`에는 접근할 수 없습니다
onBeforeRouteUpdate(async (to, from) => {
  // query나 hash만 바뀌었을 수도 있으므로 id가 바뀐 경우에만 사용자를 가져옵니다
  if (to.params.id !== from.params.id) {
    userData.value = await fetchUser(to.params.id)
  }
})
</script>

Composition API 가드는 <router-view>가 렌더링하는 어떤 컴포넌트에서도 사용할 수 있으며, 컴포넌트 내부 가드처럼 반드시 라우트 컴포넌트에서 직접 사용해야 하는 것은 아닙니다.

Vue Router는 RouterLink의 내부 동작을 composable 형태로 노출합니다. RouterLink의 props와 같은 반응형 객체를 받아, 자신만의 RouterLink 컴포넌트를 만들거나 사용자 정의 링크를 생성하는 데 사용할 수 있는 저수준 속성을 노출합니다:

vue
<script setup>
import { RouterLink, useLink } from 'vue-router'
import { computed } from 'vue'

const props = defineProps({
  // TypeScript를 사용 중이라면 @ts-ignore를 추가하세요
  ...RouterLink.props,
  inactiveClass: String,
})

const {
  // resolve된 라우트 객체
  route,
  // 링크에서 사용할 href
  href,
  // 링크가 활성 상태인지 나타내는 boolean ref
  isActive,
  // 링크가 정확히 활성 상태인지 나타내는 boolean ref
  isExactActive,
  // 링크로 이동하는 함수
  navigate,
} = useLink(props)

const isExternalLink = computed(
  () => typeof props.to === 'string' && props.to.startsWith('http')
)
</script>

RouterLink의 v-slotuseLink composable과 동일한 속성에 접근할 수 있다는 점에 유의하세요.

모두를 위한 문서 한글화