mirror of
https://github.com/nuxt/nuxt.git
synced 2025-03-09 03:03:18 +00:00
feat(nuxt)!: use paylod cache for initial data fetching by default (#3985)
Co-authored-by: Daniel Roe <daniel@roe.dev>
This commit is contained in:
parent
58386198c9
commit
323803832a
@ -16,12 +16,12 @@ Within your pages, components and plugins you can use `useAsyncData` to get acce
|
|||||||
const {
|
const {
|
||||||
data: Ref<DataT>,
|
data: Ref<DataT>,
|
||||||
pending: Ref<boolean>,
|
pending: Ref<boolean>,
|
||||||
refresh: (force?: boolean) => Promise<void>,
|
refresh: () => Promise<void>,
|
||||||
error?: any
|
error?: any
|
||||||
} = useAsyncData(
|
} = useAsyncData(
|
||||||
key: string,
|
key: string,
|
||||||
handler: (ctx?: NuxtApp) => Promise<Object>,
|
handler: (ctx?: NuxtApp) => Promise<Object>,
|
||||||
options?: {
|
options?: {
|
||||||
lazy: boolean,
|
lazy: boolean,
|
||||||
server: boolean,
|
server: boolean,
|
||||||
watch: WatchSource[]
|
watch: WatchSource[]
|
||||||
@ -40,6 +40,7 @@ const {
|
|||||||
* _transform_: a function that can be used to alter `handler` function result after resolving
|
* _transform_: a function that can be used to alter `handler` function result after resolving
|
||||||
* _pick_: only pick specified keys in this array from `handler` function result
|
* _pick_: only pick specified keys in this array from `handler` function result
|
||||||
* _watch_: watch reactive sources to auto refresh
|
* _watch_: watch reactive sources to auto refresh
|
||||||
|
* _initialCache_: When set to `false`, will skip payload cache for initial fetch. (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.
|
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.
|
||||||
|
|
||||||
|
@ -21,12 +21,17 @@ export interface AsyncDataOptions<
|
|||||||
transform?: Transform
|
transform?: Transform
|
||||||
pick?: PickKeys
|
pick?: PickKeys
|
||||||
watch?: MultiWatchSources
|
watch?: MultiWatchSources
|
||||||
|
initialCache?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RefreshOptions {
|
||||||
|
_initial?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface _AsyncData<DataT> {
|
export interface _AsyncData<DataT> {
|
||||||
data: Ref<DataT>
|
data: Ref<DataT>
|
||||||
pending: Ref<boolean>
|
pending: Ref<boolean>
|
||||||
refresh: (force?: boolean) => Promise<void>
|
refresh: (opts?: RefreshOptions) => Promise<void>
|
||||||
error?: any
|
error?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +63,7 @@ export function useAsyncData<
|
|||||||
console.warn('[useAsyncData] `defer` has been renamed to `lazy`. Support for `defer` will be removed in RC.')
|
console.warn('[useAsyncData] `defer` has been renamed to `lazy`. Support for `defer` will be removed in RC.')
|
||||||
}
|
}
|
||||||
options.lazy = options.lazy ?? (options as any).defer ?? false
|
options.lazy = options.lazy ?? (options as any).defer ?? false
|
||||||
|
options.initialCache = options.initialCache ?? true
|
||||||
|
|
||||||
// Setup nuxt instance payload
|
// Setup nuxt instance payload
|
||||||
const nuxt = useNuxtApp()
|
const nuxt = useNuxtApp()
|
||||||
@ -81,11 +87,15 @@ export function useAsyncData<
|
|||||||
error: ref(nuxt.payload._errors[key] ?? null)
|
error: ref(nuxt.payload._errors[key] ?? null)
|
||||||
} as AsyncData<DataT>
|
} as AsyncData<DataT>
|
||||||
|
|
||||||
asyncData.refresh = (force?: boolean) => {
|
asyncData.refresh = (opts = {}) => {
|
||||||
// Avoid fetching same key more than once at a time
|
// Avoid fetching same key more than once at a time
|
||||||
if (nuxt._asyncDataPromises[key] && !force) {
|
if (nuxt._asyncDataPromises[key]) {
|
||||||
return nuxt._asyncDataPromises[key]
|
return nuxt._asyncDataPromises[key]
|
||||||
}
|
}
|
||||||
|
// Avoid fetching same key that is already fetched
|
||||||
|
if (opts._initial && options.initialCache && nuxt.payload.data[key] !== undefined) {
|
||||||
|
return nuxt.payload.data[key]
|
||||||
|
}
|
||||||
asyncData.pending.value = true
|
asyncData.pending.value = true
|
||||||
// TODO: Cancel previous promise
|
// TODO: Cancel previous promise
|
||||||
// TODO: Handle immediate errors
|
// TODO: Handle immediate errors
|
||||||
@ -115,11 +125,13 @@ export function useAsyncData<
|
|||||||
return nuxt._asyncDataPromises[key]
|
return nuxt._asyncDataPromises[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initialFetch = () => asyncData.refresh({ _initial: true })
|
||||||
|
|
||||||
const fetchOnServer = options.server !== false && nuxt.payload.serverRendered
|
const fetchOnServer = options.server !== false && nuxt.payload.serverRendered
|
||||||
|
|
||||||
// Server side
|
// Server side
|
||||||
if (process.server && fetchOnServer) {
|
if (process.server && fetchOnServer) {
|
||||||
const promise = asyncData.refresh()
|
const promise = initialFetch()
|
||||||
onServerPrefetch(() => promise)
|
onServerPrefetch(() => promise)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,10 +143,10 @@ export function useAsyncData<
|
|||||||
} else if (instance && (nuxt.isHydrating || options.lazy)) {
|
} else if (instance && (nuxt.isHydrating || options.lazy)) {
|
||||||
// 2. Initial load (server: false): fetch on mounted
|
// 2. Initial load (server: false): fetch on mounted
|
||||||
// 3. Navigation (lazy: true): fetch on mounted
|
// 3. Navigation (lazy: true): fetch on mounted
|
||||||
instance._nuxtOnBeforeMountCbs.push(asyncData.refresh)
|
instance._nuxtOnBeforeMountCbs.push(initialFetch)
|
||||||
} else {
|
} else {
|
||||||
// 4. Navigation (lazy: false) - or plugin usage: await fetch
|
// 4. Navigation (lazy: false) - or plugin usage: await fetch
|
||||||
asyncData.refresh()
|
initialFetch()
|
||||||
}
|
}
|
||||||
if (options.watch) {
|
if (options.watch) {
|
||||||
watch(options.watch, () => asyncData.refresh())
|
watch(options.watch, () => asyncData.refresh())
|
||||||
|
@ -7,11 +7,16 @@ import { useAsyncData } from './asyncData'
|
|||||||
|
|
||||||
export type FetchResult<ReqT extends FetchRequest> = TypedInternalResponse<ReqT, unknown>
|
export type FetchResult<ReqT extends FetchRequest> = TypedInternalResponse<ReqT, unknown>
|
||||||
|
|
||||||
export type UseFetchOptions<
|
export interface UseFetchOptions<
|
||||||
DataT,
|
DataT,
|
||||||
Transform extends _Transform<DataT, any> = _Transform<DataT, DataT>,
|
Transform extends _Transform<DataT, any> = _Transform<DataT, DataT>,
|
||||||
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
|
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
|
||||||
> = AsyncDataOptions<DataT, Transform, PickKeys> & FetchOptions & { key?: string }
|
> extends
|
||||||
|
AsyncDataOptions<DataT, Transform, PickKeys>,
|
||||||
|
FetchOptions
|
||||||
|
{
|
||||||
|
key?: string
|
||||||
|
}
|
||||||
|
|
||||||
export function useFetch<
|
export function useFetch<
|
||||||
ResT = void,
|
ResT = void,
|
||||||
@ -32,15 +37,22 @@ export function useFetch<
|
|||||||
return isRef(r) ? r.value : r
|
return isRef(r) ? r.value : r
|
||||||
})
|
})
|
||||||
|
|
||||||
const asyncData = useAsyncData(key, () => {
|
const _fetchOptions = {
|
||||||
return $fetch(_request.value, opts) as Promise<_ResT>
|
...opts,
|
||||||
}, {
|
cache: typeof opts.cache === 'boolean' ? undefined : opts.cache
|
||||||
|
}
|
||||||
|
|
||||||
|
const _asyncDataOptions: AsyncDataOptions<any> = {
|
||||||
...opts,
|
...opts,
|
||||||
watch: [
|
watch: [
|
||||||
_request,
|
_request,
|
||||||
...(opts.watch || [])
|
...(opts.watch || [])
|
||||||
]
|
]
|
||||||
})
|
}
|
||||||
|
|
||||||
|
const asyncData = useAsyncData(key, () => {
|
||||||
|
return $fetch(_request.value, _fetchOptions) as Promise<_ResT>
|
||||||
|
}, _asyncDataOptions)
|
||||||
|
|
||||||
return asyncData
|
return asyncData
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user