You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
title="Learn how to use Vue Router with the composition API"
5
+
title="Learn how to use Vue Router with the Composition API"
6
6
/>
7
7
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.
9
9
10
10
## Accessing the Router and current Route inside `setup`
11
11
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:
13
13
14
-
```js
14
+
```vue
15
+
<script setup>
15
16
import { useRouter, useRoute } from 'vue-router'
16
17
17
-
exportdefault {
18
-
setup() {
19
-
constrouter=useRouter()
20
-
constroute=useRoute()
21
-
22
-
functionpushWithQuery(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
+
})
32
29
}
30
+
</script>
33
31
```
34
32
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:
36
34
37
-
```js
35
+
```vue
36
+
<script setup>
38
37
import { useRoute } from 'vue-router'
39
38
import { ref, watch } from 'vue'
40
39
41
-
exportdefault {
42
-
setup() {
43
-
constroute=useRoute()
44
-
constuserData=ref()
45
-
46
-
// fetch the user information when params change
47
-
watch(
48
-
() =>route.params.id,
49
-
asyncnewId=> {
50
-
userData.value=awaitfetchUser(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>
55
51
```
56
52
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.
58
54
59
55
## Navigation Guards
60
56
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:
62
58
63
-
```js
59
+
```vue
60
+
<script setup>
64
61
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
65
62
import { ref } from 'vue'
66
63
67
-
exportdefault {
68
-
setup() {
69
-
// same as beforeRouteLeave option with no access to `this`
70
-
onBeforeRouteLeave((to, from) => {
71
-
constanswer=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) returnfalse
76
-
})
77
-
78
-
constuserData=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=awaitfetchUser(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>
89
83
```
90
84
91
85
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
94
88
95
89
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:
96
90
97
-
```js
91
+
```vue
92
+
<script setup>
98
93
import { RouterLink, useLink } from 'vue-router'
99
94
import { computed } from 'vue'
100
95
101
-
exportdefault {
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
Copy file name to clipboardExpand all lines: packages/docs/guide/advanced/data-fetching.md
+81-33Lines changed: 81 additions & 33 deletions
Original file line number
Diff line number
Diff line change
@@ -10,11 +10,13 @@ Technically, both are valid choices - it ultimately depends on the user experien
10
10
11
11
## Fetching After Navigation
12
12
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.
14
14
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`:
// watch the params of the route to fetch the data again
43
90
this.$watch(
44
-
() =>this.$route.params,
91
+
() => this.$route.params.id,
45
92
() => {
46
93
this.fetchData()
47
94
},
@@ -51,27 +98,29 @@ export default {
51
98
)
52
99
},
53
100
methods: {
54
-
fetchData() {
101
+
async fetchData() {
55
102
this.error = this.post = null
56
103
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 {
59
111
this.loading = false
60
-
if (err) {
61
-
this.error=err.toString()
62
-
} else {
63
-
this.post= post
64
-
}
65
-
})
112
+
}
66
113
},
67
114
},
68
115
}
116
+
</script>
69
117
```
70
118
119
+
:::
120
+
71
121
## Fetching Before Navigation
72
122
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**:
75
124
76
125
```js
77
126
exportdefault {
@@ -81,29 +130,28 @@ export default {
81
130
error:null,
82
131
}
83
132
},
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
+
asyncbeforeRouteEnter(to, from, next) {
134
+
try {
135
+
constpost=awaitgetPost(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
+
}
89
142
},
90
143
// when route changes and this component is already rendered,
0 commit comments