Skip to content

Commit

Permalink
docs: update examples to use SFCs (vuejs#2174)
Browse files Browse the repository at this point in the history
  • Loading branch information
niceplugin committed Mar 17, 2024
1 parent 79a6877 commit dd3d18b
Show file tree
Hide file tree
Showing 12 changed files with 596 additions and 325 deletions.
186 changes: 87 additions & 99 deletions docs/guide/advanced/composition-api.md
Original file line number Diff line number Diff line change
@@ -1,133 +1,121 @@
# Vue Router์™€ ์ปดํฌ์ง€์…˜ API %{#vue-router-and-the-composition-api}%
# Vue Router์™€ ์ปดํฌ์ง€์…˜ API %{#Vue-Router-and-the-Composition-API}%

<VueSchoolLink
href="https://vueschool.io/lessons/router-and-the-composition-api"
title="Learn how to use Vue Router with the composition API"
href="https://vueschool.io/lessons/router-and-the-composition-api"
title="Vue Router์™€ ์ปดํฌ์ง€์…˜ API ์‚ฌ์šฉ๋ฒ• ๋ฐฐ์šฐ๊ธฐ"
/>

Vue 3์—์„œ๋Š” `setup`๊ณผ [์ปดํฌ์ง€์…˜ API](https://vuejs.kr/guide/extras/composition-api-faq.html)๊ฐ€ ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ ํƒ์ƒ‰ ๊ฐ€๋“œ์™€ `this`์—์„œ ๋ผ์šฐํ„ฐ์— ์ ‘๊ทผํ•˜๋Š” ๊ธฐ์กด ๋ฐฉ์‹์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Vue์˜ [์ปดํฌ์ง€์…˜ API](https://vuejs.org/guide/extras/composition-api-faq.html) ๋„์ž…์€ ์ƒˆ๋กœ์šด ๊ฐ€๋Šฅ์„ฑ์„ ์—ด์—ˆ์ง€๋งŒ, Vue Router์˜ ์ „์ฒด ์ž ์žฌ๋ ฅ์„ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ `this`์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ๋Œ€์ฒดํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ ๋‚ด ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

## `setup` ๋‚ด๋ถ€์—์„œ ๋ผ์šฐํ„ฐ ๋ฐ ํ˜„์žฌ ๋ผ์šฐํŠธ์— ์ ‘๊ทผํ•˜๊ธฐ %{#accessing-the-router-and-current-route-inside-setup}%
## `setup` ๋‚ด์—์„œ ๋ผ์šฐํ„ฐ ๋ฐ ํ˜„์žฌ ๋ฃจํŠธ ์ ‘๊ทผ %{#Accessing-the-Router-and-current-Route-inside-setup}%

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

```js
```vue
<script setup>
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,
},
})
}
},
const router = useRouter()
const route = useRoute()
function pushWithQuery(query) {
router.push({
name: 'search',
query: {
...route.query,
...query,
},
})
}
</script>
```

`route`๋Š” ๋ฐ˜์‘ํ˜• ๊ฐ์ฒด์ด๋ฏ€๋กœ ํ•ด๋‹น ์†์„ฑ์€ ๋ชจ๋‘ ๊ฐ์‹œํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, `route` ๊ฐ์ฒด ์ „์ฒด๋ฅผ ๊ฐ์‹œํ•˜๋Š” ๊ฒƒ์€ ํ”ผํ•˜๋Š”๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ, ๋ณ€๊ฒฝํ•˜๋ ค๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ง์ ‘ ๊ฐ์‹œํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
`route` ๊ฐ์ฒด๋Š” ๋ฐ˜์‘ํ˜• ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ, `route` ๊ฐ์ฒด ์ „์ฒด๋ฅผ ๊ฐ์‹œํ•˜๋Š” ๊ฒƒ์€ **ํ”ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค**. ๋Œ€์‹ , ๋ณ€๊ฒฝ์„ ๊ธฐ๋Œ€ํ•˜๋Š” ์†์„ฑ๋“ค์„ ์ง์ ‘ ๊ฐ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

```js
```vue
<script setup>
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)
}
)
},
}
const route = useRoute()
const userData = ref()
// ํŒŒ๋ผ๋ฏธํ„ฐ ๋ณ€๊ฒฝ ์‹œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
watch(
() => route.params.id,
async newId => {
userData.value = await fetchUser(newId)
}
)
</script>
```

ํ…œํ”Œ๋ฆฟ ๋‚ด๋ถ€์—์„œ๋Š” ์—ฌ์ „ํžˆ `$router` ๋ฐ `$route`๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, `setup` ๋‚ด๋ถ€์—์„œ `router` ๋ฐ `route`๋ฅผ ๋ฐ˜ํ™˜ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.
ํ…œํ”Œ๋ฆฟ์—์„œ๋Š” ์—ฌ์ „ํžˆ `$router`์™€ `$route`์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ํ…œํ”Œ๋ฆฟ์—์„œ๋งŒ ์ด ๊ฐ์ฒด๋“ค์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ `useRouter`๋‚˜ `useRoute`๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

## ํƒ์ƒ‰ ๊ฐ€๋“œ %{#navigation-guards}%
## ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ %{#Navigation-Guards}%

Vue Router๋Š” ์—…๋ฐ์ดํŠธ ๋ฐ ๋ฆฌ๋ธŒ ๊ฐ€๋“œ๋ฅผ ์ปดํฌ์ง€์…˜ API ๋ฉ”์„œ๋“œ๋กœ ๋…ธ์ถœํ•˜๋ฏ€๋กœ, `setup` ํ•จ์ˆ˜์—์„œ ์ปดํฌ๋„ŒํŠธ ๋‚ด ํƒ์ƒ‰ ๊ฐ€๋“œ๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Vue Router๋Š” ์ปดํฌ์ง€์…˜ API ํ•จ์ˆ˜๋กœ ์—…๋ฐ์ดํŠธ์™€ ๋– ๋‚จ ๊ฐ€๋“œ๋ฅผ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค:

```js
```vue
<script setup>
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)
}
})
},
}
// 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>
```

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

## `useLink`
## `useLink` %{#useLink}%

Vue ๋ผ์šฐํ„ฐ๋Š” RouterLink์˜ ๋‚ด๋ถ€ ๋™์ž‘์„ ์ปดํฌ์ €๋ธ”๋กœ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” `RouterLink`์˜ props์™€ ๊ฐ™์€ ๋ฐ˜์‘ ๊ฐ์ฒด๋ฅผ ํ—ˆ์šฉํ•˜๊ณ  low-level ์†์„ฑ์„ ๋…ธ์ถœํ•˜์—ฌ ์ž์‹ ๋งŒ์˜ `RouterLink` ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌ์ถ•ํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž ์ง€์ • ๋งํฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค:
Vue Router๋Š” RouterLink์˜ ๋‚ด๋ถ€ ๋™์ž‘์„ ์ปดํฌ์ €๋ธ”๋กœ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” `RouterLink`์˜ props์™€ ๊ฐ™์€ ๋ฐ˜์‘ํ˜• ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„๋“ค์ด๋ฉฐ, ์ž์‹ ๋งŒ์˜ `RouterLink` ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌ์ถ•ํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž ์ •์˜ ๋งํฌ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์ €์ˆ˜์ค€ ์†์„ฑ๋“ค์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค:

```js
```vue
<script setup>
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 }
},
}
const props = defineProps({
// TypeScript ์‚ฌ์šฉ ์‹œ @ts-ignore ์ถ”๊ฐ€
...RouterLink.props,
inactiveClass: String,
})
const {
// ํ•ด๊ฒฐ๋œ ๋ผ์šฐํŠธ ๊ฐ์ฒด
route,
// ๋งํฌ์—์„œ ์‚ฌ์šฉํ•  href
href,
// ๋งํฌ๊ฐ€ ํ™œ์„ฑํ™”๋˜์—ˆ๋Š”์ง€ ๋‚˜ํƒ€๋‚ด๋Š” ๋ถˆ๋ฆฐ ref
isActive,
// ๋งํฌ๊ฐ€ ์ •ํ™•ํžˆ ํ™œ์„ฑํ™”๋˜์—ˆ๋Š”์ง€ ๋‚˜ํƒ€๋‚ด๋Š” ๋ถˆ๋ฆฐ ref
isExactActive,
// ๋งํฌ๋กœ ์ด๋™ํ•˜๋Š” ํ•จ์ˆ˜
navigate
} = useLink(props)
const isExternalLink = computed(
() => typeof props.to === 'string' && props.to.startsWith('http')
)
</script>
```

RouterLink์˜ `v-slot`์€ `useLink` ์ปดํฌ์ €๋ธ”๊ณผ ๋™์ผํ•œ ์†์„ฑ์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
RouterLink์˜ `v-slot`์€ `useLink` ์ปดํฌ์ €๋ธ”๊ณผ ๋™์ผํ•œ ์†์„ฑ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Loading

0 comments on commit dd3d18b

Please sign in to comment.