@nuxt/docs-nightly 4.2.1-29360990.b3040970 → 4.2.1-29362163.2a087817
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/1.getting-started/10.data-fetching.md +12 -12
- package/2.guide/3.going-further/1.experimental-features.md +4 -4
- package/3.api/2.composables/use-async-data.md +74 -11
- package/3.api/2.composables/use-nuxt-app.md +1 -1
- package/3.api/2.composables/use-nuxt-data.md +1 -1
- package/3.api/2.composables/use-request-fetch.md +1 -1
- package/3.api/3.utils/refresh-cookie.md +1 -1
- package/package.json +1 -1
|
@@ -194,10 +194,10 @@ The `useAsyncData` composable is a great way to wrap and wait for multiple `$fet
|
|
|
194
194
|
|
|
195
195
|
```vue
|
|
196
196
|
<script setup lang="ts">
|
|
197
|
-
const { data: discounts, status } = await useAsyncData('cart-discount', async () => {
|
|
197
|
+
const { data: discounts, status } = await useAsyncData('cart-discount', async (_nuxtApp, { signal }) => {
|
|
198
198
|
const [coupons, offers] = await Promise.all([
|
|
199
|
-
$fetch('/cart/coupons'),
|
|
200
|
-
$fetch('/cart/offers'),
|
|
199
|
+
$fetch('/cart/coupons', { signal }),
|
|
200
|
+
$fetch('/cart/offers', { signal }),
|
|
201
201
|
])
|
|
202
202
|
|
|
203
203
|
return { coupons, offers }
|
|
@@ -372,8 +372,8 @@ The following options **must be consistent** across all calls with the same key:
|
|
|
372
372
|
|
|
373
373
|
```ts
|
|
374
374
|
// ❌ This will trigger a development warning
|
|
375
|
-
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false })
|
|
376
|
-
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })
|
|
375
|
+
const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: false })
|
|
376
|
+
const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: true })
|
|
377
377
|
```
|
|
378
378
|
|
|
379
379
|
The following options **can safely differ** without triggering warnings:
|
|
@@ -385,16 +385,16 @@ The following options **can safely differ** without triggering warnings:
|
|
|
385
385
|
|
|
386
386
|
```ts
|
|
387
387
|
// ✅ This is allowed
|
|
388
|
-
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: true })
|
|
389
|
-
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: false })
|
|
388
|
+
const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: true })
|
|
389
|
+
const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: false })
|
|
390
390
|
```
|
|
391
391
|
|
|
392
392
|
If you need independent instances, use different keys:
|
|
393
393
|
|
|
394
394
|
```ts
|
|
395
395
|
// These are completely independent instances
|
|
396
|
-
const { data: users1 } = useAsyncData('users-1', () => $fetch('/api/users'))
|
|
397
|
-
const { data: users2 } = useAsyncData('users-2', () => $fetch('/api/users'))
|
|
396
|
+
const { data: users1 } = useAsyncData('users-1', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }))
|
|
397
|
+
const { data: users2 } = useAsyncData('users-2', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }))
|
|
398
398
|
```
|
|
399
399
|
|
|
400
400
|
#### Reactive Keys
|
|
@@ -804,10 +804,10 @@ while (true) {
|
|
|
804
804
|
When requests don't rely on each other, you can make them in parallel with `Promise.all()` to boost performance.
|
|
805
805
|
|
|
806
806
|
```ts
|
|
807
|
-
const { data } = await useAsyncData(() => {
|
|
807
|
+
const { data } = await useAsyncData((_nuxtApp, { signal }) => {
|
|
808
808
|
return Promise.all([
|
|
809
|
-
$fetch('/api/comments/'),
|
|
810
|
-
$fetch('/api/author/12'),
|
|
809
|
+
$fetch('/api/comments/', { signal }),
|
|
810
|
+
$fetch('/api/author/12', { signal }),
|
|
811
811
|
])
|
|
812
812
|
})
|
|
813
813
|
|
|
@@ -405,12 +405,12 @@ should do this automatically for you.)
|
|
|
405
405
|
// This would be unsafe in a dynamic page (e.g. `[slug].vue`) because the route slug makes a difference
|
|
406
406
|
// to the data fetched, but Nuxt can't know that because it's not reflected in the key.
|
|
407
407
|
const route = useRoute()
|
|
408
|
-
const { data } = await useAsyncData(async () => {
|
|
409
|
-
return await $fetch(`/api/my-page/${route.params.slug}
|
|
408
|
+
const { data } = await useAsyncData(async (_nuxtApp, { signal }) => {
|
|
409
|
+
return await $fetch(`/api/my-page/${route.params.slug}`, { signal })
|
|
410
410
|
})
|
|
411
411
|
// Instead, you should use a key that uniquely identifies the data fetched.
|
|
412
|
-
const { data } = await useAsyncData(route.params.slug, async () => {
|
|
413
|
-
return await $fetch(`/api/my-page/${route.params.slug}
|
|
412
|
+
const { data } = await useAsyncData(route.params.slug, async (_nuxtApp, { signal }) => {
|
|
413
|
+
return await $fetch(`/api/my-page/${route.params.slug}`, { signal })
|
|
414
414
|
})
|
|
415
415
|
```
|
|
416
416
|
|
|
@@ -18,9 +18,9 @@ Within your pages, components, and plugins you can use useAsyncData to get acces
|
|
|
18
18
|
|
|
19
19
|
```vue [app/pages/index.vue]
|
|
20
20
|
<script setup lang="ts">
|
|
21
|
-
const { data, status, error, refresh, clear } = await useAsyncData(
|
|
21
|
+
const { data, status, pending, error, refresh, clear } = await useAsyncData(
|
|
22
22
|
'mountains',
|
|
23
|
-
() => $fetch('https://api.nuxtjs.dev/mountains'),
|
|
23
|
+
(_nuxtApp, { signal }) => $fetch('https://api.nuxtjs.dev/mountains', { signal }),
|
|
24
24
|
)
|
|
25
25
|
</script>
|
|
26
26
|
```
|
|
@@ -30,7 +30,7 @@ If you're using a custom useAsyncData wrapper, do not await it in the composable
|
|
|
30
30
|
::
|
|
31
31
|
|
|
32
32
|
::note
|
|
33
|
-
`data`, `status` and `error` are Vue refs and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` and `clear` are plain functions.
|
|
33
|
+
`data`, `status`, `pending` and `error` are Vue refs and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` and `clear` are plain functions.
|
|
34
34
|
::
|
|
35
35
|
|
|
36
36
|
### Watch Params
|
|
@@ -42,10 +42,11 @@ The built-in `watch` option allows automatically rerunning the fetcher function
|
|
|
42
42
|
const page = ref(1)
|
|
43
43
|
const { data: posts } = await useAsyncData(
|
|
44
44
|
'posts',
|
|
45
|
-
() => $fetch('https://fakeApi.com/posts', {
|
|
45
|
+
(_nuxtApp, { signal }) => $fetch('https://fakeApi.com/posts', {
|
|
46
46
|
params: {
|
|
47
47
|
page: page.value,
|
|
48
48
|
},
|
|
49
|
+
signal,
|
|
49
50
|
}), {
|
|
50
51
|
watch: [page],
|
|
51
52
|
},
|
|
@@ -70,6 +71,64 @@ const { data: user } = useAsyncData(
|
|
|
70
71
|
</script>
|
|
71
72
|
```
|
|
72
73
|
|
|
74
|
+
### Make your `handler` abortable
|
|
75
|
+
|
|
76
|
+
You can make your `handler` function abortable by using the `signal` provided in the second argument. This is useful for cancelling requests when they are no longer needed, such as when a user navigates away from a page. `$fetch` natively supports abort signals.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const { data, error } = await useAsyncData(
|
|
80
|
+
'users',
|
|
81
|
+
(_nuxtApp, { signal }) => $fetch('/api/users', { signal }),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
refresh() // will actually cancel the $fetch request (if dedupe: cancel)
|
|
85
|
+
refresh() // will actually cancel the $fetch request (if dedupe: cancel)
|
|
86
|
+
refresh()
|
|
87
|
+
|
|
88
|
+
clear() // will cancel the latest pending handler
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
You can also pass an `AbortSignal` to the `refresh`/`execute` function to cancel individual requests manually.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const { refresh } = await useAsyncData(
|
|
95
|
+
'users',
|
|
96
|
+
(_nuxtApp, { signal }) => $fetch('/api/users', { signal }),
|
|
97
|
+
)
|
|
98
|
+
let abortController: AbortController | undefined
|
|
99
|
+
|
|
100
|
+
function handleUserAction () {
|
|
101
|
+
abortController = new AbortController()
|
|
102
|
+
refresh({ signal: abortController.signal })
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function handleCancel () {
|
|
106
|
+
abortController?.abort() // aborts the ongoing refresh request
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If your `handler` function does not support abort signals, you can implement your own abort logic using the `signal` provided.
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const { data, error } = await useAsyncData(
|
|
114
|
+
'users',
|
|
115
|
+
(_nuxtApp, { signal }) => {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
signal?.addEventListener('abort', () => {
|
|
118
|
+
reject(new Error('Request aborted'))
|
|
119
|
+
})
|
|
120
|
+
return Promise.resolve(callback.call(this, yourHandler)).then(resolve, reject)
|
|
121
|
+
})
|
|
122
|
+
},
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The handler signal will be aborted when:
|
|
127
|
+
|
|
128
|
+
- A new request is made with `dedupe: 'cancel'`
|
|
129
|
+
- The `clear` function is called
|
|
130
|
+
- The `options.timeout` duration is exceeded
|
|
131
|
+
|
|
73
132
|
::warning
|
|
74
133
|
[`useAsyncData`](/docs/4.x/api/composables/use-async-data) is a reserved function name transformed by the compiler, so you should not name your own function [`useAsyncData`](/docs/4.x/api/composables/use-async-data).
|
|
75
134
|
::
|
|
@@ -116,7 +175,7 @@ You can use `useLazyAsyncData` to have the same behavior as `lazy: true` with `u
|
|
|
116
175
|
|
|
117
176
|
### Shared State and Option Consistency
|
|
118
177
|
|
|
119
|
-
When using the same key for multiple `useAsyncData` calls, they will share the same `data`, `error` and `
|
|
178
|
+
When using the same key for multiple `useAsyncData` calls, they will share the same `data`, `error`, `status` and `pending` refs. This ensures consistency across components but requires option consistency.
|
|
120
179
|
|
|
121
180
|
The following options **must be consistent** across all calls with the same key:
|
|
122
181
|
- `handler` function
|
|
@@ -135,12 +194,12 @@ The following options **can differ** without triggering warnings:
|
|
|
135
194
|
|
|
136
195
|
```ts
|
|
137
196
|
// ❌ This will trigger a development warning
|
|
138
|
-
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false })
|
|
139
|
-
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })
|
|
197
|
+
const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: false })
|
|
198
|
+
const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: true })
|
|
140
199
|
|
|
141
200
|
// ✅ This is allowed
|
|
142
|
-
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: true })
|
|
143
|
-
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: false })
|
|
201
|
+
const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: true })
|
|
202
|
+
const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: false })
|
|
144
203
|
```
|
|
145
204
|
|
|
146
205
|
::tip
|
|
@@ -159,6 +218,7 @@ Keyed state created using `useAsyncData` can be retrieved across your Nuxt appli
|
|
|
159
218
|
- `pending`: the request is in progress
|
|
160
219
|
- `success`: the request has completed successfully
|
|
161
220
|
- `error`: the request has failed
|
|
221
|
+
- `pending`: a `Ref<boolean>` that is `true` while the request is in progress (that is, while `status.value === 'pending'`).
|
|
162
222
|
- `clear`: a function that can be used to set `data` to `undefined` (or the value of `options.default()` if provided), set `error` to `undefined`, set `status` to `idle`, and mark any currently pending requests as cancelled.
|
|
163
223
|
|
|
164
224
|
By default, Nuxt waits until a `refresh` is finished before it can be executed again.
|
|
@@ -170,13 +230,15 @@ If you have not fetched data on the server (for example, with `server: false`),
|
|
|
170
230
|
## Type
|
|
171
231
|
|
|
172
232
|
```ts [Signature]
|
|
233
|
+
export type AsyncDataHandler<ResT> = (nuxtApp: NuxtApp, options: { signal: AbortSignal }) => Promise<ResT>
|
|
234
|
+
|
|
173
235
|
export function useAsyncData<DataT, DataE> (
|
|
174
|
-
handler:
|
|
236
|
+
handler: AsyncDataHandler<DataT>,
|
|
175
237
|
options?: AsyncDataOptions<DataT>
|
|
176
238
|
): AsyncData<DataT, DataE>
|
|
177
239
|
export function useAsyncData<DataT, DataE> (
|
|
178
240
|
key: MaybeRefOrGetter<string>,
|
|
179
|
-
handler:
|
|
241
|
+
handler: AsyncDataHandler<DataT>,
|
|
180
242
|
options?: AsyncDataOptions<DataT>
|
|
181
243
|
): Promise<AsyncData<DataT, DataE>>
|
|
182
244
|
|
|
@@ -206,6 +268,7 @@ type AsyncData<DataT, ErrorT> = {
|
|
|
206
268
|
clear: () => void
|
|
207
269
|
error: Ref<ErrorT | undefined>
|
|
208
270
|
status: Ref<AsyncDataRequestStatus>
|
|
271
|
+
pending: Ref<boolean>
|
|
209
272
|
}
|
|
210
273
|
|
|
211
274
|
interface AsyncDataExecuteOptions {
|
|
@@ -108,7 +108,7 @@ Nuxt exposes the following properties through `ssrContext`:
|
|
|
108
108
|
::code-group
|
|
109
109
|
```vue [app/app.vue]
|
|
110
110
|
<script setup lang="ts">
|
|
111
|
-
const { data } = await useAsyncData('count', () => $fetch('/api/count'))
|
|
111
|
+
const { data } = await useAsyncData('count', (_nuxtApp, { signal }) => $fetch('/api/count', { signal }))
|
|
112
112
|
</script>
|
|
113
113
|
```
|
|
114
114
|
```ts [server/api/count.ts]
|
|
@@ -67,7 +67,7 @@ Optimistic Updates is a technique where the user interface is updated immediatel
|
|
|
67
67
|
```vue [app/pages/todos.vue]
|
|
68
68
|
<script setup lang="ts">
|
|
69
69
|
// We can access same data later using 'todos' key
|
|
70
|
-
const { data } = await useAsyncData('todos', () => $fetch('/api/todos'))
|
|
70
|
+
const { data } = await useAsyncData('todos', (_nuxtApp, { signal }) => $fetch('/api/todos', { signal }))
|
|
71
71
|
</script>
|
|
72
72
|
```
|
|
73
73
|
|
|
@@ -33,7 +33,7 @@ const { data: forwarded } = await useAsyncData(() => requestFetch('/api/cookies'
|
|
|
33
33
|
|
|
34
34
|
// This will NOT forward anything
|
|
35
35
|
// Result: { cookies: {} }
|
|
36
|
-
const { data: notForwarded } = await useAsyncData(() => $fetch('/api/cookies'))
|
|
36
|
+
const { data: notForwarded } = await useAsyncData((_nuxtApp, { signal }) => $fetch('/api/cookies', { signal }))
|
|
37
37
|
</script>
|
|
38
38
|
```
|
|
39
39
|
|
|
@@ -36,7 +36,7 @@ const loggedIn = computed(() => !!tokenCookie.value)
|
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
::note{to="/docs/4.x/guide/going-further/experimental-features#cookiestore"}
|
|
39
|
-
|
|
39
|
+
Since [Nuxt v3.12.0](https://github.com/nuxt/nuxt/releases/tag/v3.12.0), the experimental `cookieStore` option is enabled by default. It automatically refreshes the `useCookie` value when cookies change in the browser.
|
|
40
40
|
::
|
|
41
41
|
|
|
42
42
|
## Type
|