Skip to content

Complete guide to

Mastering Pinia

written by its creator

Vue Router와 컴포지션 API

Vue 3에서는 setup컴포지션 API가 도입되었습니다. 따라서 컴포넌트 내부의 탐색 가드와 this에서 라우터에 접근하는 기존 방식을 대체할 수 있는 몇 가지 새로운 함수를 사용할 수 있습니다.

setup 내부에서 라우터 및 현재 라우트에 접근하기

setup 내부에서는 this에 접근할 수 없기 때문에, this.$router 또는 this.$route에 접근할 수 없습니다. 접근하기 위해서는 useRouter 또는 useRoute 함수를 사용해야 합니다.

js
import { useRouter, useRoute } from 'vue-router'

export default {
  setup() {
    const router = useRouter()
    const route = useRoute()

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

route는 반응형 객체이므로 해당 속성은 모두 감시할 수 있으므로, route 객체 전체를 감시하는 것은 피하는게 좋습니다. 대부분의 경우, 변경하려는 파라미터를 직접 감시하는 것이 좋습니다.

js
import { useRoute } from 'vue-router'
import { ref, watch } from 'vue'

export default {
  setup() {
    const route = useRoute()
    const userData = ref()

    // 파라미터가 변경될 때 유저 정보를 가져오기.
    watch(
      () => route.params.id,
      async newId => {
        userData.value = await fetchUser(newId)
      }
    )
  },
}

템플릿 내부에서는 여전히 $router$route로 접근할 수 있으므로, setup 내부에서 routerroute를 반환할 필요는 없습니다.

Vue Router는 업데이트 및 리브 가드를 컴포지션 API 메서드로 노출하므로, setup 함수에서 컴포넌트 내 탐색 가드를 계속 사용할 수 있습니다.

js
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
import { ref } from 'vue'

export default {
  setup() {
    // `this`에 접근 권한이 없으며, beforeRouteLeave 옵션과 동일
    onBeforeRouteLeave((to, from) => {
      const answer = window.confirm(
        '정말 떠나시겠습니까? 저장되지 않은 변경 사항이 있습니다!'
      )
      // 탐색을 취소하고 같은 페이지에 머물기
      if (!answer) return false
    })

    const userData = ref()

    // `this`에 접근 권한이 없으며, beforeRouteUpdate 옵션과 동일
    onBeforeRouteUpdate(async (to, from) => {
      // 쿼리 또는 해시가 변경되었을 수 있으므로, ID가 변경된 경우에만 유저 정보를 가져오기.
      if (to.params.id !== from.params.id) {
        userData.value = await fetchUser(to.params.id)
      }
    })
  },
}

컴포지션 API 가드는 <router-view>로 렌더링된 모든 컴포넌트에서도 사용할 수 있으므로, 라우트 컴포넌트 내에서만 사용해야 하는 것은 아닙니다.

Vue 라우터는 RouterLink의 내부 동작을 컴포저블로 노출합니다. 이는 RouterLink의 props와 같은 반응 객체를 허용하고 low-level 속성을 노출하여 자신만의 RouterLink 컴포넌트를 구축하거나 사용자 지정 링크를 생성합니다:

js
import { RouterLink, useLink } from 'vue-router'
import { computed } from 'vue'

export default {
  name: 'AppLink',

  props: {
    // TypeScript를 사용한다면, @ts-ignore 추가가 필요함
    ...RouterLink.props,
    inactiveClass: String,
  },

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

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

    return { isExternalLink, href, navigate, isActive }
  },
}

RouterLink의 v-slotuseLink 컴포저블과 동일한 속성에 대한 액세스를 제공합니다.

Translated by router.vuejs.kr