mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-21 21:25:11 +00:00
fix(nuxt): recreate asyncData
when immediate
is disabled (#20980)
This commit is contained in:
parent
a28ee6b014
commit
6f7d86be78
@ -25,11 +25,11 @@ function useAsyncData<DataT, DataE>(
|
||||
type AsyncDataOptions<DataT> = {
|
||||
server?: boolean
|
||||
lazy?: boolean
|
||||
immediate?: boolean
|
||||
default?: () => DataT | Ref<DataT> | null
|
||||
transform?: (input: DataT) => DataT
|
||||
pick?: string[]
|
||||
watch?: WatchSource[]
|
||||
immediate?: boolean
|
||||
}
|
||||
|
||||
type AsyncData<DataT, ErrorT> = {
|
||||
@ -53,13 +53,13 @@ type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
|
||||
* **key**: a unique key to ensure that data fetching can be properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file name and line number of the instance of [`useAsyncData`](/docs/api/composables/use-async-data) will be generated for you.
|
||||
* **handler**: an asynchronous function that returns a value
|
||||
* **options**:
|
||||
* _lazy_: whether to resolve the async function after loading the route, instead of blocking client-side navigation (defaults to `false`)
|
||||
* _default_: a factory function to set the default value of the data, before the async function resolves - particularly useful with the `lazy: true` option
|
||||
* _server_: whether to fetch the data on the server (defaults to `true`)
|
||||
* _lazy_: whether to resolve the async function after loading the route, instead of blocking client-side navigation (defaults to `false`)
|
||||
* _immediate_: when set to `false`, will prevent the request from firing immediately. (defaults to `true`)
|
||||
* _default_: a factory function to set the default value of the `data`, before the async function resolves - useful with the `lazy: true` or `immediate: false` option
|
||||
* _transform_: a function that can be used to alter `handler` function result after resolving
|
||||
* _pick_: only pick specified keys in this array from the `handler` function result
|
||||
* _watch_: watch reactive sources to auto-refresh
|
||||
* _immediate_: When set to `false`, will prevent the request from firing immediately. (defaults to `true`)
|
||||
|
||||
Under the hood, `lazy: false` uses `<Suspense>` to block the loading of the route before the data has been fetched. Consider using `lazy: true` and implementing a loading state instead for a snappier user experience.
|
||||
|
||||
|
@ -29,7 +29,7 @@ type UseFetchOptions<DataT> = {
|
||||
default?: () => DataT
|
||||
transform?: (input: DataT) => DataT
|
||||
pick?: string[]
|
||||
watch?: WatchSource[]
|
||||
watch?: WatchSource[] | false
|
||||
}
|
||||
|
||||
type AsyncData<DataT, ErrorT> = {
|
||||
@ -63,14 +63,15 @@ type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
|
||||
All fetch options can be given a `computed` or `ref` value. These will be watched and new requests made automatically with any new values if they are updated.
|
||||
::
|
||||
|
||||
* **Options (from [`useAsyncData`](/docs/api/composables/use-async-data) )**:
|
||||
* `key`: a unique key to ensure that data fetching can be properly de-duplicated across requests, if not provided, it will be generated based on the static code location where [`useAsyncData`](/docs/api/composables/use-async-data) is used.
|
||||
* `server`: Whether to fetch the data on the server (defaults to `true`).
|
||||
* `default`: A factory function to set the default value of the data, before the async function resolves - particularly useful with the `lazy: true` option.
|
||||
* `pick`: Only pick specified keys in this array from the `handler` function result.
|
||||
* `watch`: Watch an array of reactive sources and auto-refresh the fetch result when they change. Fetch options and URL are watched by default. You can completely ignore reactive sources by using `watch: false`. Together with `immediate: false`, this allows for a fully-manual `useFetch`.
|
||||
* `transform`: A function that can be used to alter `handler` function result after resolving.
|
||||
* `immediate`: When set to `false`, will prevent the request from firing immediately. (defaults to `true`)
|
||||
* **Options (from `useAsyncData`)**:
|
||||
* `key`: a unique key to ensure that data fetching can be properly de-duplicated across requests, if not provided, it will be generated based on the static code location where `useAsyncData` is used.
|
||||
* `server`: whether to fetch the data on the server (defaults to `true`)
|
||||
* `lazy`: whether to resolve the async function after loading the route, instead of blocking client-side navigation (defaults to `false`)
|
||||
* `immediate`: when set to `false`, will prevent the request from firing immediately. (defaults to `true`)
|
||||
* `default`: a factory function to set the default value of the `data`, before the async function resolves - useful with the `lazy: true` or `immediate: false` option
|
||||
* `transform`: a function that can be used to alter `handler` function result after resolving
|
||||
* `pick`: only pick specified keys in this array from the `handler` function result
|
||||
* `watch`: watch an array of reactive sources and auto-refresh the fetch result when they change. Fetch options and URL are watched by default. You can completely ignore reactive sources by using `watch: false`. Together with `immediate: false`, this allows for a fully-manual `useFetch`.
|
||||
|
||||
::alert{type=warning}
|
||||
If you provide a function or ref as the `url` parameter, or if you provide functions as arguments to the `options` parameter, then the [`useFetch`](/docs/api/composables/use-fetch) call will not match other [`useFetch`](/docs/api/composables/use-fetch) calls elsewhere in your codebase, even if the options seem to be identical. If you wish to force a match, you may provide your own key in `options`.
|
||||
|
@ -145,7 +145,7 @@ export function useAsyncData<
|
||||
const hasCachedData = () => getCachedData() !== undefined
|
||||
|
||||
// Create or use a shared asyncData entity
|
||||
if (!nuxt._asyncData[key]) {
|
||||
if (!nuxt._asyncData[key] || !options.immediate) {
|
||||
nuxt._asyncData[key] = {
|
||||
data: ref(getCachedData() ?? options.default!()),
|
||||
pending: ref(!hasCachedData()),
|
||||
|
@ -1848,6 +1848,26 @@ describe.skipIf(isWindows)('useAsyncData', () => {
|
||||
await page.locator('#status5-values').getByText('idle,pending,success').waitFor()
|
||||
await page.close()
|
||||
})
|
||||
|
||||
it('data is null after navigation when immediate false', async () => {
|
||||
const page = await createPage('/useAsyncData/immediate-remove-unmounted')
|
||||
await page.waitForLoadState('networkidle')
|
||||
await page.waitForFunction(() => window.useNuxtApp?.()._route.fullPath === '/useAsyncData/immediate-remove-unmounted')
|
||||
expect(await page.locator('#immediate-data').getByText('null').textContent()).toBe('null')
|
||||
|
||||
await page.click('#execute-btn')
|
||||
expect(await page.locator('#immediate-data').getByText(',').textContent()).not.toContain('null')
|
||||
|
||||
await page.click('#to-index')
|
||||
|
||||
await page.click('#to-immediate-remove-unmounted')
|
||||
expect(await page.locator('#immediate-data').getByText('null').textContent()).toBe('null')
|
||||
|
||||
await page.click('#execute-btn')
|
||||
expect(await page.locator('#immediate-data').getByText(',').textContent()).not.toContain('null')
|
||||
|
||||
await page.close()
|
||||
})
|
||||
})
|
||||
|
||||
describe.runIf(isDev())('component testing', () => {
|
||||
|
3
test/fixtures/basic/pages/index.vue
vendored
3
test/fixtures/basic/pages/index.vue
vendored
@ -26,6 +26,9 @@
|
||||
<NuxtLink id="islands" to="/islands">
|
||||
islands
|
||||
</NuxtLink>
|
||||
<NuxtLink id="to-immediate-remove-unmounted" to="/useAsyncData/immediate-remove-unmounted">
|
||||
Immediate remove unmounted
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/chunk-error" :prefetch="false">
|
||||
Chunk error
|
||||
</NuxtLink>
|
||||
|
22
test/fixtures/basic/pages/useAsyncData/immediate-remove-unmounted.vue
vendored
Normal file
22
test/fixtures/basic/pages/useAsyncData/immediate-remove-unmounted.vue
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>immediate-remove-unmounted.vue</div>
|
||||
<div id="immediate-data">
|
||||
{{ data === null ? "null" : data }}
|
||||
</div>
|
||||
<button id="execute-btn" @click="execute">
|
||||
execute
|
||||
</button>
|
||||
<NuxtLink id="to-index" to="/">
|
||||
index
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { data, execute } = await useAsyncData('immediateFalse', () => $fetch('/api/random'), { immediate: false })
|
||||
|
||||
if (data.value !== null) {
|
||||
throw new Error('Initial data should be null: ' + data.value)
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user