Skip to content

Vue Router์™€ Composition API โ€‹

Vue์˜ Composition API์˜ ๋„์ž…์œผ๋กœ ์ƒˆ๋กœ์šด ๊ฐ€๋Šฅ์„ฑ์ด ์—ด๋ ธ์ง€๋งŒ, Vue Router์˜ ๋ชจ๋“  ์ž ์žฌ๋ ฅ์„ ํ™œ์šฉํ•˜๋ ค๋ฉด this์— ๋Œ€ํ•œ ์ ‘๊ทผ๊ณผ ์ปดํฌ๋„ŒํŠธ ๋‚ด ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ๋ฅผ ๋Œ€์ฒดํ•  ๋ช‡ ๊ฐ€์ง€ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

setup ๋‚ด๋ถ€์—์„œ Router์™€ ํ˜„์žฌ Route์— ์ ‘๊ทผํ•˜๊ธฐ โ€‹

setup ๋‚ด๋ถ€์—์„œ๋Š” this์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—, this.$router๋‚˜ this.$route์— ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ , useRouter์™€ useRoute ์ปดํฌ์ €๋ธ”์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

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 ๊ฐ์ฒด๋ฅผ ๊ฐ์‹œํ•˜๋Š” ๊ฒƒ์€ ํ”ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‹ , ๋ณ€๊ฒฝ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š” ์†์„ฑ๋งŒ ์ง์ ‘ ๊ฐ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

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์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ํ•ด๋‹น ๊ฐ์ฒด๋“ค์ด ํ…œํ”Œ๋ฆฟ์—์„œ๋งŒ ํ•„์š”ํ•˜๋‹ค๋ฉด useRouter๋‚˜ useRoute๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

Vue Router๋Š” Composition API ํ•จ์ˆ˜๋กœ ์—…๋ฐ์ดํŠธ ๋ฐ ์ดํƒˆ ๊ฐ€๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

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

// beforeRouteLeave ์˜ต์…˜๊ณผ ๋™์ผํ•˜์ง€๋งŒ `this`์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค
onBeforeRouteLeave((to, from) => {
  const answer = window.confirm(
    '์ •๋ง๋กœ ์ด ํŽ˜์ด์ง€๋ฅผ ๋– ๋‚˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์ €์žฅ๋˜์ง€ ์•Š์€ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค!'
  )
  // ๋„ค๋น„๊ฒŒ์ด์…˜์„ ์ทจ์†Œํ•˜๊ณ  ๊ฐ™์€ ํŽ˜์ด์ง€์— ๋จธ๋ฌด๋ฆ…๋‹ˆ๋‹ค
  if (!answer) return false
})

const userData = ref()

// beforeRouteUpdate ์˜ต์…˜๊ณผ ๋™์ผํ•˜์ง€๋งŒ `this`์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค
onBeforeRouteUpdate(async (to, from) => {
  // id๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉ์ž๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ์ฟผ๋ฆฌ๋‚˜ ํ•ด์‹œ๋งŒ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค
  if (to.params.id !== from.params.id) {
    userData.value = await fetchUser(to.params.id)
  }
})
</script>

Composition API ๊ฐ€๋“œ๋Š” <router-view>์— ์˜ํ•ด ๋ Œ๋”๋ง๋˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ปดํฌ๋„ŒํŠธ ๋‚ด ๊ฐ€๋“œ์ฒ˜๋Ÿผ ๋ฐ˜๋“œ์‹œ ๋ผ์šฐํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ง์ ‘ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.

Vue Router๋Š” RouterLink์˜ ๋‚ด๋ถ€ ๋™์ž‘์„ ์ปดํฌ์ €๋ธ”๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” 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 {
  // ํ•ด์„๋œ ๋ผ์šฐํŠธ ๊ฐ์ฒด
  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-slot์€ useLink ์ปดํฌ์ €๋ธ”๊ณผ ๋™์ผํ•œ ์†์„ฑ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”.

๋ชจ๋‘๋ฅผ ์œ„ํ•œ ๋ฌธ์„œ ํ•œ๊ธ€ํ™”