mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(nuxt): add immediate
option for useAsyncData
and useFetch
(#5500)
Co-authored-by: Pooya Parsa <pooya@pi0.io>
This commit is contained in:
parent
577a7b681e
commit
fc2be9ed42
@ -23,6 +23,7 @@ type AsyncDataOptions<DataT> = {
|
||||
pick?: string[]
|
||||
watch?: WatchSource[]
|
||||
initialCache?: boolean
|
||||
immediate?: boolean
|
||||
}
|
||||
|
||||
interface RefreshOptions {
|
||||
@ -32,6 +33,7 @@ interface RefreshOptions {
|
||||
type AsyncData<DataT, ErrorT> = {
|
||||
data: Ref<DataT | null>
|
||||
pending: Ref<boolean>
|
||||
execute: () => Promise<void>
|
||||
refresh: (opts?: RefreshOptions) => Promise<void>
|
||||
error: Ref<ErrorT | null>
|
||||
}
|
||||
@ -51,6 +53,7 @@ type AsyncData<DataT, ErrorT> = {
|
||||
* _pick_: only pick specified keys in this array from the `handler` function result
|
||||
* _watch_: watch reactive sources to auto-refresh
|
||||
* _initialCache_: When set to `false`, will skip payload cache for initial fetch. (defaults to `true`)
|
||||
* _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.
|
||||
|
||||
@ -58,7 +61,7 @@ Under the hood, `lazy: false` uses `<Suspense>` to block the loading of the rout
|
||||
|
||||
* **data**: the result of the asynchronous function that is passed in
|
||||
* **pending**: a boolean indicating whether the data is still being fetched
|
||||
* **refresh**: a function that can be used to refresh the data returned by the `handler` function
|
||||
* **refresh**/**execute**: a function that can be used to refresh the data returned by the `handler` function
|
||||
* **error**: an error object if the data fetching failed
|
||||
|
||||
By default, Nuxt waits until a `refresh` is finished before it can be executed again.
|
||||
|
@ -19,6 +19,7 @@ type UseFetchOptions = {
|
||||
baseURL?: string
|
||||
server?: boolean
|
||||
lazy?: boolean
|
||||
immediate?: boolean
|
||||
default?: () => DataT
|
||||
transform?: (input: DataT) => DataT
|
||||
pick?: string[]
|
||||
@ -30,6 +31,7 @@ type AsyncData<DataT> = {
|
||||
data: Ref<DataT>
|
||||
pending: Ref<boolean>
|
||||
refresh: () => Promise<void>
|
||||
execute: () => Promise<void>
|
||||
error: Ref<Error | boolean>
|
||||
}
|
||||
```
|
||||
@ -51,6 +53,7 @@ type AsyncData<DataT> = {
|
||||
* `watch`: watch reactive sources to auto-refresh.
|
||||
* `initialCache`: When set to `false`, will skip payload cache for initial fetch (defaults to `true`).
|
||||
* `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`)
|
||||
|
||||
::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` call will not match other `useFetch` 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`.
|
||||
@ -60,7 +63,7 @@ If you provide a function or ref as the `url` parameter, or if you provide funct
|
||||
|
||||
* **data**: the result of the asynchronous function that is passed in.
|
||||
* **pending**: a boolean indicating whether the data is still being fetched.
|
||||
* **refresh**: a function that can be used to refresh the data returned by the `handler` function.
|
||||
* **refresh**/**execute** : a function that can be used to refresh the data returned by the `handler` function.
|
||||
* **error**: an error object if the data fetching failed.
|
||||
|
||||
By default, Nuxt waits until a `refresh` is finished before it can be executed again.
|
||||
|
@ -29,16 +29,18 @@ export interface AsyncDataOptions<
|
||||
pick?: PickKeys
|
||||
watch?: MultiWatchSources
|
||||
initialCache?: boolean
|
||||
immediate?: boolean
|
||||
}
|
||||
|
||||
export interface RefreshOptions {
|
||||
export interface AsyncDataExecuteOptions {
|
||||
_initial?: boolean
|
||||
}
|
||||
|
||||
export interface _AsyncData<DataT, ErrorT> {
|
||||
data: Ref<DataT | null>
|
||||
pending: Ref<boolean>
|
||||
refresh: (opts?: RefreshOptions) => Promise<void>
|
||||
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
||||
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
||||
error: Ref<ErrorT | null>
|
||||
}
|
||||
|
||||
@ -94,6 +96,7 @@ export function useAsyncData<
|
||||
}
|
||||
options.lazy = options.lazy ?? (options as any).defer ?? false
|
||||
options.initialCache = options.initialCache ?? true
|
||||
options.immediate = options.immediate ?? true
|
||||
|
||||
// Setup nuxt instance payload
|
||||
const nuxt = useNuxtApp()
|
||||
@ -111,7 +114,7 @@ export function useAsyncData<
|
||||
// TODO: Else, Soemhow check for confliciting keys with different defaults or fetcher
|
||||
const asyncData = { ...nuxt._asyncData[key] } as AsyncData<DataT, DataE>
|
||||
|
||||
asyncData.refresh = (opts = {}) => {
|
||||
asyncData.refresh = asyncData.execute = (opts = {}) => {
|
||||
// Avoid fetching same key more than once at a time
|
||||
if (nuxt._asyncDataPromises[key]) {
|
||||
return nuxt._asyncDataPromises[key]
|
||||
@ -160,7 +163,7 @@ export function useAsyncData<
|
||||
const fetchOnServer = options.server !== false && nuxt.payload.serverRendered
|
||||
|
||||
// Server side
|
||||
if (process.server && fetchOnServer) {
|
||||
if (process.server && fetchOnServer && options.immediate) {
|
||||
const promise = initialFetch()
|
||||
onServerPrefetch(() => promise)
|
||||
}
|
||||
@ -184,11 +187,11 @@ export function useAsyncData<
|
||||
if (fetchOnServer && nuxt.isHydrating && key in nuxt.payload.data) {
|
||||
// 1. Hydration (server: true): no fetch
|
||||
asyncData.pending.value = false
|
||||
} else if (instance && ((nuxt.payload.serverRendered && nuxt.isHydrating) || options.lazy)) {
|
||||
} else if (instance && ((nuxt.payload.serverRendered && nuxt.isHydrating) || options.lazy) && options.immediate) {
|
||||
// 2. Initial load (server: false): fetch on mounted
|
||||
// 3. Initial load or navigation (lazy: true): fetch on mounted
|
||||
instance._nuxtOnBeforeMountCbs.push(initialFetch)
|
||||
} else {
|
||||
} else if (options.immediate) {
|
||||
// 4. Navigation (lazy: false) - or plugin usage: await fetch
|
||||
initialFetch()
|
||||
}
|
||||
|
36
test/fixtures/basic/pages/useAsyncData/immediate.vue
vendored
Normal file
36
test/fixtures/basic/pages/useAsyncData/immediate.vue
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div>
|
||||
Single
|
||||
<div>
|
||||
data: {{ data }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const called = ref(0)
|
||||
const { data, execute } = await useAsyncData(() => Promise.resolve(++called.value), { immediate: false })
|
||||
|
||||
if (called.value !== 0) {
|
||||
throw new Error('Handled should have not been called')
|
||||
}
|
||||
|
||||
if (process.server && data.value !== null) {
|
||||
throw new Error('Initial data should be null: ' + data.value)
|
||||
}
|
||||
|
||||
await execute()
|
||||
await execute()
|
||||
|
||||
if (process.server && called.value as number !== 2) {
|
||||
throw new Error('Should have been called once after execute (server) but called ' + called.value + ' times')
|
||||
}
|
||||
|
||||
if (process.client && called.value as number !== 2) {
|
||||
throw new Error('Should have been called once after execute (client) but called ' + called.value + ' times')
|
||||
}
|
||||
|
||||
if (data.value !== 2) {
|
||||
throw new Error('Data should be 1 after execute')
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user