Skip to content

Commit 1204b57

Browse files
committed
docs: update examples to use SFCs
1 parent 8618943 commit 1204b57

File tree

12 files changed

+542
-265
lines changed

12 files changed

+542
-265
lines changed

packages/docs/guide/advanced/composition-api.md

Lines changed: 79 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2,90 +2,84 @@
22

33
<VueSchoolLink
44
href="https://vueschool.io/lessons/router-and-the-composition-api"
5-
title="Learn how to use Vue Router with the composition API"
5+
title="Learn how to use Vue Router with the Composition API"
66
/>
77

8-
The introduction of `setup` and Vue's [Composition API](https://vuejs.org/guide/extras/composition-api-faq.html), open up new possibilities but to be able to get the full potential out of Vue Router, we will need to use a few new functions to replace access to `this` and in-component navigation guards.
8+
The introduction of Vue's [Composition API](https://vuejs.org/guide/extras/composition-api-faq.html) opened up new possibilities, but to be able to get the full potential out of Vue Router, we will need to use a few new functions to replace access to `this` and in-component navigation guards.
99

1010
## Accessing the Router and current Route inside `setup`
1111

12-
Because we don't have access to `this` inside of `setup`, we cannot directly access `this.$router` or `this.$route` anymore. Instead we use the `useRouter` and `useRoute` functions:
12+
Because we don't have access to `this` inside of `setup`, we cannot directly access `this.$router` or `this.$route`. Instead, we use the `useRouter` and `useRoute` functions:
1313

14-
```js
14+
```vue
15+
<script setup>
1516
import { useRouter, useRoute } from 'vue-router'
1617
17-
export default {
18-
setup() {
19-
const router = useRouter()
20-
const route = useRoute()
21-
22-
function pushWithQuery(query) {
23-
router.push({
24-
name: 'search',
25-
query: {
26-
...route.query,
27-
...query,
28-
},
29-
})
30-
}
31-
},
18+
const router = useRouter()
19+
const route = useRoute()
20+
21+
function pushWithQuery(query) {
22+
router.push({
23+
name: 'search',
24+
query: {
25+
...route.query,
26+
...query,
27+
},
28+
})
3229
}
30+
</script>
3331
```
3432

35-
The `route` object is a reactive object, so any of its properties can be watched and you should **avoid watching the whole `route`** object. In most scenarios, you should directly watch the param you are expecting to change
33+
The `route` object is a reactive object. In most scenarios, you should **avoid watching the whole `route`** object. Instead, you can directly watch the properties you are expecting to change:
3634

37-
```js
35+
```vue
36+
<script setup>
3837
import { useRoute } from 'vue-router'
3938
import { ref, watch } from 'vue'
4039
41-
export default {
42-
setup() {
43-
const route = useRoute()
44-
const userData = ref()
45-
46-
// fetch the user information when params change
47-
watch(
48-
() => route.params.id,
49-
async newId => {
50-
userData.value = await fetchUser(newId)
51-
}
52-
)
53-
},
54-
}
40+
const route = useRoute()
41+
const userData = ref()
42+
43+
// fetch the user information when params change
44+
watch(
45+
() => route.params.id,
46+
async newId => {
47+
userData.value = await fetchUser(newId)
48+
}
49+
)
50+
</script>
5551
```
5652

57-
Note we still have access to `$router` and `$route` in templates, so there is no need to return `router` or `route` inside of `setup`.
53+
Note we still have access to `$router` and `$route` in templates, so there's no need to use `useRouter` or `useRoute` if we only need those object in the template.
5854

5955
## Navigation Guards
6056

61-
While you can still use in-component navigation guards with a `setup` function, Vue Router exposes update and leave guards as Composition API functions:
57+
Vue Router exposes update and leave guards as Composition API functions:
6258

63-
```js
59+
```vue
60+
<script setup>
6461
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
6562
import { ref } from 'vue'
6663
67-
export default {
68-
setup() {
69-
// same as beforeRouteLeave option with no access to `this`
70-
onBeforeRouteLeave((to, from) => {
71-
const answer = window.confirm(
72-
'Do you really want to leave? you have unsaved changes!'
73-
)
74-
// cancel the navigation and stay on the same page
75-
if (!answer) return false
76-
})
77-
78-
const userData = ref()
79-
80-
// same as beforeRouteUpdate option with no access to `this`
81-
onBeforeRouteUpdate(async (to, from) => {
82-
// only fetch the user if the id changed as maybe only the query or the hash changed
83-
if (to.params.id !== from.params.id) {
84-
userData.value = await fetchUser(to.params.id)
85-
}
86-
})
87-
},
88-
}
64+
// same as beforeRouteLeave option but with no access to `this`
65+
onBeforeRouteLeave((to, from) => {
66+
const answer = window.confirm(
67+
'Do you really want to leave? you have unsaved changes!'
68+
)
69+
// cancel the navigation and stay on the same page
70+
if (!answer) return false
71+
})
72+
73+
const userData = ref()
74+
75+
// same as beforeRouteUpdate option but with no access to `this`
76+
onBeforeRouteUpdate(async (to, from) => {
77+
// only fetch the user if the id changed as maybe only the query or the hash changed
78+
if (to.params.id !== from.params.id) {
79+
userData.value = await fetchUser(to.params.id)
80+
}
81+
})
82+
</script>
8983
```
9084

9185
Composition API guards can also be used in any component rendered by `<router-view>`, they don't have to be used directly on the route component like in-component guards.
@@ -94,40 +88,34 @@ Composition API guards can also be used in any component rendered by `<router-vi
9488

9589
Vue Router exposes the internal behavior of RouterLink as a composable. It accepts a reactive object like the props of `RouterLink` and exposes low-level properties to build your own `RouterLink` component or generate custom links:
9690

97-
```js
91+
```vue
92+
<script setup>
9893
import { RouterLink, useLink } from 'vue-router'
9994
import { computed } from 'vue'
10095
101-
export default {
102-
name: 'AppLink',
103-
104-
props: {
105-
// add @ts-ignore if using TypeScript
106-
...RouterLink.props,
107-
inactiveClass: String,
108-
},
109-
110-
setup(props) {
111-
const {
112-
// the resolved route object
113-
route,
114-
// the href to use in a link
115-
href,
116-
// boolean ref indicating if the link is active
117-
isActive,
118-
// boolean ref indicating if the link is exactly active
119-
isExactActive,
120-
// function to navigate to the link
121-
navigate
122-
} = useLink(props)
123-
124-
const isExternalLink = computed(
125-
() => typeof props.to === 'string' && props.to.startsWith('http')
126-
)
127-
128-
return { isExternalLink, href, navigate, isActive }
129-
},
130-
}
96+
const props = defineProps({
97+
// add @ts-ignore if using TypeScript
98+
...RouterLink.props,
99+
inactiveClass: String,
100+
})
101+
102+
const {
103+
// the resolved route object
104+
route,
105+
// the href to use in a link
106+
href,
107+
// boolean ref indicating if the link is active
108+
isActive,
109+
// boolean ref indicating if the link is exactly active
110+
isExactActive,
111+
// function to navigate to the link
112+
navigate
113+
} = useLink(props)
114+
115+
const isExternalLink = computed(
116+
() => typeof props.to === 'string' && props.to.startsWith('http')
117+
)
118+
</script>
131119
```
132120

133121
Note that the RouterLink's `v-slot` gives access to the same properties as the `useLink` composable.

packages/docs/guide/advanced/data-fetching.md

Lines changed: 81 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ Technically, both are valid choices - it ultimately depends on the user experien
1010

1111
## Fetching After Navigation
1212

13-
When using this approach, we navigate and render the incoming component immediately, and fetch data in the component's `created` hook. It gives us the opportunity to display a loading state while the data is being fetched over the network, and we can also handle loading differently for each view.
13+
When using this approach, we navigate and render the incoming component immediately, and fetch data in the component itself. It gives us the opportunity to display a loading state while the data is being fetched over the network, and we can also handle loading differently for each view.
1414

15-
Let's assume we have a `Post` component that needs to fetch the data for a post based on `$route.params.id`:
15+
Let's assume we have a `Post` component that needs to fetch the data for a post based on `route.params.id`:
1616

17-
```html
17+
::: code-group
18+
19+
```vue [Composition API]
1820
<template>
1921
<div class="post">
2022
<div v-if="loading" class="loading">Loading...</div>
@@ -27,9 +29,54 @@ Let's assume we have a `Post` component that needs to fetch the data for a post
2729
</div>
2830
</div>
2931
</template>
32+
33+
<script setup>
34+
import { ref, watch } from 'vue'
35+
import { useRoute } from 'vue-router'
36+
import { getPost } from './api.js'
37+
38+
const route = useRoute()
39+
40+
const loading = ref(false)
41+
const post = ref(null)
42+
const error = ref(null)
43+
44+
// watch the params of the route to fetch the data again
45+
watch(() => route.params.id, fetchData, { immediate: true })
46+
47+
async function fetchData() {
48+
error.value = post.value = null
49+
loading.value = true
50+
51+
try {
52+
// replace `getPost` with your data fetching util / API wrapper
53+
post.value = await getPost(route.params.id)
54+
} catch (err) {
55+
error.value = err.toString()
56+
} finally {
57+
loading.value = false
58+
}
59+
}
60+
</script>
3061
```
3162

32-
```js
63+
```vue [Options API]
64+
<template>
65+
<div class="post">
66+
<div v-if="loading" class="loading">Loading...</div>
67+
68+
<div v-if="error" class="error">{{ error }}</div>
69+
70+
<div v-if="post" class="content">
71+
<h2>{{ post.title }}</h2>
72+
<p>{{ post.body }}</p>
73+
</div>
74+
</div>
75+
</template>
76+
77+
<script>
78+
import { getPost } from './api.js'
79+
3380
export default {
3481
data() {
3582
return {
@@ -41,7 +88,7 @@ export default {
4188
created() {
4289
// watch the params of the route to fetch the data again
4390
this.$watch(
44-
() => this.$route.params,
91+
() => this.$route.params.id,
4592
() => {
4693
this.fetchData()
4794
},
@@ -51,27 +98,29 @@ export default {
5198
)
5299
},
53100
methods: {
54-
fetchData() {
101+
async fetchData() {
55102
this.error = this.post = null
56103
this.loading = true
57-
// replace `getPost` with your data fetching util / API wrapper
58-
getPost(this.$route.params.id, (err, post) => {
104+
105+
try {
106+
// replace `getPost` with your data fetching util / API wrapper
107+
this.post = await getPost(this.$route.params.id)
108+
} catch (err) {
109+
this.error = err.toString()
110+
} finally {
59111
this.loading = false
60-
if (err) {
61-
this.error = err.toString()
62-
} else {
63-
this.post = post
64-
}
65-
})
112+
}
66113
},
67114
},
68115
}
116+
</script>
69117
```
70118

119+
:::
120+
71121
## Fetching Before Navigation
72122

73-
With this approach we fetch the data before actually navigating to the new
74-
route. We can perform the data fetching in the `beforeRouteEnter` guard in the incoming component, and only call `next` when the fetch is complete. The callback passed to `next` will be called **after the component is mounted**:
123+
With this approach we fetch the data before actually navigating to the new route. We can perform the data fetching in the `beforeRouteEnter` guard in the incoming component, and only call `next` when the fetch is complete. The callback passed to `next` will be called **after the component is mounted**:
75124

76125
```js
77126
export default {
@@ -81,29 +130,28 @@ export default {
81130
error: null,
82131
}
83132
},
84-
beforeRouteEnter(to, from, next) {
85-
getPost(to.params.id, (err, post) => {
86-
// `setData` is a method defined below
87-
next(vm => vm.setData(err, post))
88-
})
133+
async beforeRouteEnter(to, from, next) {
134+
try {
135+
const post = await getPost(to.params.id)
136+
// `setPost` is a method defined below
137+
next(vm => vm.setPost(post))
138+
} catch (err) {
139+
// `setError` is a method defined below
140+
next(vm => vm.setError(err))
141+
}
89142
},
90143
// when route changes and this component is already rendered,
91144
// the logic will be slightly different.
92-
async beforeRouteUpdate(to, from) {
145+
beforeRouteUpdate(to, from) {
93146
this.post = null
94-
try {
95-
this.post = await getPost(to.params.id)
96-
} catch (error) {
97-
this.error = error.toString()
98-
}
147+
getPost(to.params.id).then(this.setPost).catch(this.setError)
99148
},
100149
methods: {
101-
setData(error, post) {
102-
if (error) {
103-
this.error = error
104-
} else {
105-
this.post = post
106-
}
150+
setPost(post) {
151+
this.post = post
152+
},
153+
setError(err) {
154+
this.error = err.toString()
107155
}
108156
}
109157
}

packages/docs/guide/advanced/dynamic-routing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ The page will still show the `Article` component, we need to manually call `rout
3030

3131
```js
3232
router.addRoute({ path: '/about', component: About })
33-
// we could also use this.$route or route = useRoute() (inside a setup)
33+
// we could also use this.$route or useRoute()
3434
router.replace(router.currentRoute.value.fullPath)
3535
```
3636

0 commit comments

Comments
 (0)