2023-10-16 12:56:23 +00:00
import { getCurrentInstance , onBeforeMount , onServerPrefetch , onUnmounted , ref , shallowRef , toRef , unref , watch } from 'vue'
2022-03-16 22:49:30 +00:00
import type { Ref , WatchSource } from 'vue'
2022-12-11 21:44:52 +00:00
import type { NuxtApp } from '../nuxt'
import { useNuxtApp } from '../nuxt'
2023-12-23 14:22:58 +00:00
import { toArray } from '../utils'
2024-01-18 10:01:39 +00:00
import type { NuxtError } from './error'
2022-11-02 09:07:28 +00:00
import { createError } from './error'
2023-05-22 23:09:05 +00:00
import { onNuxtReady } from './ready'
2021-01-18 12:46:19 +00:00
2023-10-18 14:25:25 +00:00
// @ts-expect-error virtual file
import { asyncDataDefaults } from '#build/nuxt.config.mjs'
2023-06-09 21:38:14 +00:00
export type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
2021-11-15 12:09:07 +00:00
export type _Transform < Input = any , Output = any > = ( input : Input ) = > Output
2021-10-11 22:36:50 +00:00
2022-06-08 19:45:12 +00:00
export type PickFrom < T , K extends Array < string > > = T extends Array < any >
? T
: T extends Record < string , any >
2024-01-18 10:01:39 +00:00
? keyof T extends K [ number ]
? T // Exact same keys as the target, skip Pick
: K [ number ] extends never
? T
: Pick < T , K [ number ] >
: T
2022-06-08 19:45:12 +00:00
2022-11-16 14:27:24 +00:00
export type KeysOf < T > = Array <
T extends T // Include all keys of union types, not just common keys
? keyof T extends string
2024-01-18 10:01:39 +00:00
? keyof T
: never
2022-11-16 14:27:24 +00:00
: never
>
2021-10-11 22:36:50 +00:00
export type KeyOfRes < Transform extends _Transform > = KeysOf < ReturnType < Transform > >
2023-04-03 12:36:14 +00:00
export type MultiWatchSources = ( WatchSource < unknown > | object ) [ ]
2022-03-16 22:49:30 +00:00
2021-10-11 22:36:50 +00:00
export interface AsyncDataOptions <
2023-03-11 22:36:10 +00:00
ResT ,
DataT = ResT ,
2023-04-14 12:53:21 +00:00
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
2023-05-20 22:19:50 +00:00
DefaultT = null ,
2022-08-15 13:55:46 +00:00
> {
2024-01-18 16:02:52 +00:00
/ * *
* Whether to fetch on the server side .
* @default true
* /
2021-01-18 12:46:19 +00:00
server? : boolean
2024-01-18 16:02:52 +00:00
/ * *
* Whether to resolve the async function after loading the route , instead of blocking client - side navigation
* @default false
* /
2021-11-15 12:09:07 +00:00
lazy? : boolean
2024-01-18 16:02:52 +00:00
/ * *
* a factory function to set the default value of the data , before the async function resolves - useful with the ` lazy: true ` or ` immediate: false ` options
* /
2023-05-20 22:19:50 +00:00
default ? : ( ) = > DefaultT | Ref < DefaultT >
2024-01-18 16:02:52 +00:00
/ * *
* Provide a function which returns cached data .
* A ` null ` or ` undefined ` return value will trigger a fetch .
* Default is ` key => nuxt.isHydrating ? nuxt.payload.data[key] : nuxt.static.data[key] ` which only caches data when payloadExtraction is enabled .
* /
2023-10-16 19:54:39 +00:00
getCachedData ? : ( key : string ) = > DataT
2024-01-18 16:02:52 +00:00
/ * *
* A function that can be used to alter handler function result after resolving
* /
2023-05-20 22:19:50 +00:00
transform? : _Transform < ResT , DataT >
2024-01-18 16:02:52 +00:00
/ * *
* Only pick specified keys in this array from the handler function result
* /
2021-10-11 22:36:50 +00:00
pick? : PickKeys
2024-01-18 16:02:52 +00:00
/ * *
* Watch reactive sources to auto - refresh when changed
* /
2022-03-16 22:49:30 +00:00
watch? : MultiWatchSources
2024-01-18 16:02:52 +00:00
/ * *
* When set to false , will prevent the request from firing immediately
* @default true
* /
2022-09-07 09:47:40 +00:00
immediate? : boolean
2024-01-18 16:02:52 +00:00
/ * *
* Return data in a deep ref object ( it is true by default ) . It can be set to false to return data in a shallow ref object , which can improve performance if your data does not need to be deeply reactive .
* /
2023-10-16 12:56:23 +00:00
deep? : boolean
2024-01-18 16:02:52 +00:00
/ * *
* Avoid fetching the same key more than once at a time
* @default 'cancel'
* /
2023-12-14 11:08:43 +00:00
dedupe ? : 'cancel' | 'defer'
2022-03-31 10:24:28 +00:00
}
2022-09-07 09:47:40 +00:00
export interface AsyncDataExecuteOptions {
2022-03-31 10:24:28 +00:00
_initial? : boolean
2024-01-19 23:50:16 +00:00
// TODO: remove boolean option in Nuxt 4
2022-10-10 10:33:16 +00:00
/ * *
* Force a refresh , even if there is already a pending request . Previous requests will
* not be cancelled , but their result will not affect the data / pending state - and any
* previously awaited promises will not resolve until this new request resolves .
2023-12-14 11:08:43 +00:00
*
* Instead of using ` boolean ` values , use ` cancel ` for ` true ` and ` defer ` for ` false ` .
* Boolean values will be removed in a future release .
2022-10-10 10:33:16 +00:00
* /
2023-12-14 11:08:43 +00:00
dedupe? : boolean | 'cancel' | 'defer'
2021-01-18 12:46:19 +00:00
}
2022-04-06 16:02:45 +00:00
export interface _AsyncData < DataT , ErrorT > {
2023-05-20 22:19:50 +00:00
data : Ref < DataT >
2021-02-03 18:14:30 +00:00
pending : Ref < boolean >
2024-02-02 14:40:07 +00:00
refresh : ( opts? : AsyncDataExecuteOptions ) = > Promise < void >
execute : ( opts? : AsyncDataExecuteOptions ) = > Promise < void >
2022-08-12 17:47:58 +00:00
error : Ref < ErrorT | null >
2023-06-09 21:38:14 +00:00
status : Ref < AsyncDataRequestStatus >
2021-01-18 12:46:19 +00:00
}
2022-04-06 16:02:45 +00:00
export type AsyncData < Data , Error > = _AsyncData < Data , Error > & Promise < _AsyncData < Data , Error > >
2021-04-03 10:03:20 +00:00
2024-01-19 23:50:16 +00:00
// TODO: remove boolean option in Nuxt 4
2023-12-14 11:08:43 +00:00
const isDefer = ( dedupe? : boolean | 'cancel' | 'defer' ) = > dedupe === 'defer' || dedupe === false
2024-01-18 16:02:52 +00:00
/ * *
* Provides access to data that resolves asynchronously in an SSR - friendly composable .
* See { @link https : //nuxt.com/docs/api/composables/use-async-data}
2024-01-19 17:03:30 +00:00
* @since 3.0 . 0
2024-01-18 16:02:52 +00:00
* @param handler An asynchronous function that must return a truthy value ( for example , it should not be ` undefined ` or ` null ` ) or the request may be duplicated on the client side .
* @param options customize the behavior of useAsyncData
* /
2022-07-07 16:26:04 +00:00
export function useAsyncData <
2023-03-11 22:36:10 +00:00
ResT ,
2023-12-14 12:41:40 +00:00
NuxtErrorDataT = unknown ,
2023-03-11 22:36:10 +00:00
DataT = ResT ,
2023-05-20 22:19:50 +00:00
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
DefaultT = null ,
2022-07-07 16:26:04 +00:00
> (
2023-03-11 22:36:10 +00:00
handler : ( ctx? : NuxtApp ) = > Promise < ResT > ,
2023-05-20 22:19:50 +00:00
options? : AsyncDataOptions < ResT , DataT , PickKeys , DefaultT >
2023-12-14 12:41:40 +00:00
) : AsyncData < PickFrom < DataT , PickKeys > | DefaultT , ( NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError < NuxtErrorDataT > ) | null >
2024-01-18 16:02:52 +00:00
/ * *
* Provides access to data that resolves asynchronously in an SSR - friendly composable .
* See { @link https : //nuxt.com/docs/api/composables/use-async-data}
* @param handler An asynchronous function that must return a truthy value ( for example , it should not be ` undefined ` or ` null ` ) or the request may be duplicated on the client side .
* @param options customize the behavior of useAsyncData
* /
2023-07-23 08:24:54 +00:00
export function useAsyncData <
ResT ,
2023-12-14 12:41:40 +00:00
NuxtErrorDataT = unknown ,
2023-07-23 08:24:54 +00:00
DataT = ResT ,
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
DefaultT = DataT ,
> (
handler : ( ctx? : NuxtApp ) = > Promise < ResT > ,
options? : AsyncDataOptions < ResT , DataT , PickKeys , DefaultT >
2023-12-14 12:41:40 +00:00
) : AsyncData < PickFrom < DataT , PickKeys > | DefaultT , ( NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError < NuxtErrorDataT > ) | null >
2024-01-18 16:02:52 +00:00
/ * *
* Provides access to data that resolves asynchronously in an SSR - friendly composable .
* See { @link https : //nuxt.com/docs/api/composables/use-async-data}
* @param key A unique key to ensure that data fetching can be properly de - duplicated across requests .
* @param handler An asynchronous function that must return a truthy value ( for example , it should not be ` undefined ` or ` null ` ) or the request may be duplicated on the client side .
* @param options customize the behavior of useAsyncData
* /
2021-10-11 22:36:50 +00:00
export function useAsyncData <
2023-03-11 22:36:10 +00:00
ResT ,
2023-12-14 12:41:40 +00:00
NuxtErrorDataT = unknown ,
2023-03-11 22:36:10 +00:00
DataT = ResT ,
2023-05-20 22:19:50 +00:00
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
DefaultT = null ,
2021-10-11 22:36:50 +00:00
> (
key : string ,
2023-03-11 22:36:10 +00:00
handler : ( ctx? : NuxtApp ) = > Promise < ResT > ,
2023-05-20 22:19:50 +00:00
options? : AsyncDataOptions < ResT , DataT , PickKeys , DefaultT >
2023-12-14 12:41:40 +00:00
) : AsyncData < PickFrom < DataT , PickKeys > | DefaultT , ( NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError < NuxtErrorDataT > ) | null >
2024-01-18 16:02:52 +00:00
/ * *
* Provides access to data that resolves asynchronously in an SSR - friendly composable .
* See { @link https : //nuxt.com/docs/api/composables/use-async-data}
* @param key A unique key to ensure that data fetching can be properly de - duplicated across requests .
* @param handler An asynchronous function that must return a truthy value ( for example , it should not be ` undefined ` or ` null ` ) or the request may be duplicated on the client side .
* @param options customize the behavior of useAsyncData
* /
2023-07-23 08:24:54 +00:00
export function useAsyncData <
ResT ,
2023-12-14 12:41:40 +00:00
NuxtErrorDataT = unknown ,
2023-07-23 08:24:54 +00:00
DataT = ResT ,
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
DefaultT = DataT ,
> (
key : string ,
handler : ( ctx? : NuxtApp ) = > Promise < ResT > ,
options? : AsyncDataOptions < ResT , DataT , PickKeys , DefaultT >
2023-12-14 12:41:40 +00:00
) : AsyncData < PickFrom < DataT , PickKeys > | DefaultT , ( NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError < NuxtErrorDataT > ) | null >
2022-07-07 16:26:04 +00:00
export function useAsyncData <
2023-03-11 22:36:10 +00:00
ResT ,
2023-12-14 12:41:40 +00:00
NuxtErrorDataT = unknown ,
2023-03-11 22:36:10 +00:00
DataT = ResT ,
2023-05-20 22:19:50 +00:00
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
DefaultT = null ,
2023-12-14 12:41:40 +00:00
> ( . . . args : any [ ] ) : AsyncData < PickFrom < DataT , PickKeys > , ( NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError < NuxtErrorDataT > ) | null > {
2022-07-07 16:26:04 +00:00
const autoKey = typeof args [ args . length - 1 ] === 'string' ? args . pop ( ) : undefined
if ( typeof args [ 0 ] !== 'string' ) { args . unshift ( autoKey ) }
// eslint-disable-next-line prefer-const
2024-01-18 10:01:39 +00:00
let [ key , _handler , options = { } ] = args as [ string , ( ctx? : NuxtApp ) = > Promise < ResT > , AsyncDataOptions < ResT , DataT , PickKeys , DefaultT > ]
2022-07-07 16:26:04 +00:00
2021-10-08 14:21:55 +00:00
// Validate arguments
if ( typeof key !== 'string' ) {
2022-07-07 16:26:04 +00:00
throw new TypeError ( '[nuxt] [asyncData] key must be a string.' )
2021-10-08 14:21:55 +00:00
}
2024-01-18 10:01:39 +00:00
if ( typeof _handler !== 'function' ) {
2022-07-07 16:26:04 +00:00
throw new TypeError ( '[nuxt] [asyncData] handler must be a function.' )
2021-01-18 12:46:19 +00:00
}
2023-10-16 19:54:39 +00:00
// Setup nuxt instance payload
const nuxt = useNuxtApp ( )
2024-01-18 10:01:39 +00:00
// When prerendering, share payload data automatically between requests
const handler = import . meta . client || ! import . meta . prerender || ! nuxt . ssrContext ? . _sharedPrerenderCache ? _handler : async ( ) = > {
const value = await nuxt . ssrContext ! . _sharedPrerenderCache ! . get ( key )
if ( value ) { return value as ResT }
const promise = nuxt . runWithContext ( _handler )
nuxt . ssrContext ! . _sharedPrerenderCache ! . set ( key , promise )
return promise
}
2023-10-16 19:54:39 +00:00
// Used to get default values
const getDefault = ( ) = > null
const getDefaultCachedData = ( ) = > nuxt . isHydrating ? nuxt . payload . data [ key ] : nuxt . static . data [ key ]
2021-10-08 14:21:55 +00:00
// Apply defaults
2022-07-06 22:12:31 +00:00
options . server = options . server ? ? true
2023-05-20 22:19:50 +00:00
options . default = options . default ? ? ( getDefault as ( ) = > DefaultT )
2023-10-16 19:54:39 +00:00
options . getCachedData = options . getCachedData ? ? getDefaultCachedData
2022-07-06 22:12:31 +00:00
2022-11-16 02:26:35 +00:00
options . lazy = options . lazy ? ? false
2022-09-07 09:47:40 +00:00
options . immediate = options . immediate ? ? true
2023-10-18 14:25:25 +00:00
options . deep = options . deep ? ? asyncDataDefaults . deep
2023-12-14 11:08:43 +00:00
options . dedupe = options . dedupe ? ? 'cancel'
2021-04-03 10:03:20 +00:00
2024-01-19 23:50:16 +00:00
if ( import . meta . dev && typeof options . dedupe === 'boolean' ) {
console . warn ( '[nuxt] `boolean` values are deprecated for the `dedupe` option of `useAsyncData` and will be removed in the future. Use \'cancel\' or \'defer\' instead.' )
}
2023-10-16 19:54:39 +00:00
const hasCachedData = ( ) = > ! [ null , undefined ] . includes ( options . getCachedData ! ( key ) as any )
2022-04-05 11:51:07 +00:00
2022-08-30 10:34:09 +00:00
// Create or use a shared asyncData entity
2023-08-24 12:06:29 +00:00
if ( ! nuxt . _asyncData [ key ] || ! options . immediate ) {
2023-09-27 13:43:53 +00:00
nuxt . payload . _errors [ key ] ? ? = null
2023-10-18 14:25:25 +00:00
const _ref = options . deep ? ref : shallowRef
2023-10-16 12:56:23 +00:00
2022-08-30 10:34:09 +00:00
nuxt . _asyncData [ key ] = {
2023-10-16 19:54:39 +00:00
data : _ref ( options . getCachedData ! ( key ) ? ? options . default ! ( ) ) ,
2022-11-10 13:27:59 +00:00
pending : ref ( ! hasCachedData ( ) ) ,
2023-06-09 21:38:14 +00:00
error : toRef ( nuxt . payload . _errors , key ) ,
status : ref ( 'idle' )
2022-08-30 10:34:09 +00:00
}
}
2023-09-27 13:43:53 +00:00
2023-02-12 19:16:42 +00:00
// TODO: Else, somehow check for conflicting keys with different defaults or fetcher
2023-12-14 12:41:40 +00:00
const asyncData = { . . . nuxt . _asyncData [ key ] } as AsyncData < DataT | DefaultT , ( NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError < NuxtErrorDataT > ) >
2021-03-17 09:17:18 +00:00
2022-09-07 09:47:40 +00:00
asyncData . refresh = asyncData . execute = ( opts = { } ) = > {
2022-03-31 10:24:28 +00:00
if ( nuxt . _asyncDataPromises [ key ] ) {
2023-12-14 11:08:43 +00:00
if ( isDefer ( opts . dedupe ? ? options . dedupe ) ) {
2022-10-10 10:33:16 +00:00
// Avoid fetching same key more than once at a time
2023-10-16 19:54:39 +00:00
return nuxt . _asyncDataPromises [ key ] !
2022-10-10 10:33:16 +00:00
}
( nuxt . _asyncDataPromises [ key ] as any ) . cancelled = true
2021-01-18 12:46:19 +00:00
}
2022-03-31 10:24:28 +00:00
// Avoid fetching same key that is already fetched
2023-05-17 13:23:52 +00:00
if ( ( opts . _initial || ( nuxt . isHydrating && opts . _initial !== false ) ) && hasCachedData ( ) ) {
2023-10-16 19:54:39 +00:00
return Promise . resolve ( options . getCachedData ! ( key ) )
2022-03-31 10:24:28 +00:00
}
2021-10-08 14:21:55 +00:00
asyncData . pending . value = true
2023-06-09 21:38:14 +00:00
asyncData . status . value = 'pending'
2021-11-24 19:59:04 +00:00
// TODO: Cancel previous promise
2023-03-11 22:36:10 +00:00
const promise = new Promise < ResT > (
2022-08-09 21:48:48 +00:00
( resolve , reject ) = > {
try {
resolve ( handler ( nuxt ) )
} catch ( err ) {
reject ( err )
}
} )
2023-03-11 22:36:10 +00:00
. then ( ( _result ) = > {
2022-10-10 10:33:16 +00:00
// If this request is cancelled, resolve to the latest request.
if ( ( promise as any ) . cancelled ) { return nuxt . _asyncDataPromises [ key ] }
2023-03-11 22:36:10 +00:00
let result = _result as unknown as DataT
2021-10-11 22:36:50 +00:00
if ( options . transform ) {
2023-03-11 22:36:10 +00:00
result = options . transform ( _result )
2021-10-11 22:36:50 +00:00
}
if ( options . pick ) {
2022-08-26 15:47:29 +00:00
result = pick ( result as any , options . pick ) as DataT
2021-10-11 22:36:50 +00:00
}
2023-11-08 13:28:52 +00:00
nuxt . payload . data [ key ] = result
2021-10-08 14:21:55 +00:00
asyncData . data . value = result
asyncData . error . value = null
2023-06-09 21:38:14 +00:00
asyncData . status . value = 'success'
2021-10-08 14:21:55 +00:00
} )
. catch ( ( error : any ) = > {
2022-10-10 10:33:16 +00:00
// If this request is cancelled, resolve to the latest request.
if ( ( promise as any ) . cancelled ) { return nuxt . _asyncDataPromises [ key ] }
2023-12-14 12:41:40 +00:00
asyncData . error . value = createError < NuxtErrorDataT > ( error ) as ( NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError < NuxtErrorDataT > )
2023-05-20 22:19:50 +00:00
asyncData . data . value = unref ( options . default ! ( ) )
2023-06-09 21:38:14 +00:00
asyncData . status . value = 'error'
2021-10-08 14:21:55 +00:00
} )
. finally ( ( ) = > {
2022-10-10 10:33:16 +00:00
if ( ( promise as any ) . cancelled ) { return }
2021-10-08 14:21:55 +00:00
asyncData . pending . value = false
2023-11-08 13:28:52 +00:00
2021-10-08 14:21:55 +00:00
delete nuxt . _asyncDataPromises [ key ]
} )
2022-10-10 10:33:16 +00:00
nuxt . _asyncDataPromises [ key ] = promise
2023-10-16 19:54:39 +00:00
return nuxt . _asyncDataPromises [ key ] !
2021-10-08 14:21:55 +00:00
}
2021-01-18 12:46:19 +00:00
2022-03-31 10:24:28 +00:00
const initialFetch = ( ) = > asyncData . refresh ( { _initial : true } )
2021-10-25 10:36:38 +00:00
const fetchOnServer = options . server !== false && nuxt . payload . serverRendered
2021-01-18 12:46:19 +00:00
2021-10-08 14:21:55 +00:00
// Server side
2023-08-07 22:03:40 +00:00
if ( import . meta . server && fetchOnServer && options . immediate ) {
2022-03-31 10:24:28 +00:00
const promise = initialFetch ( )
2022-12-10 22:44:29 +00:00
if ( getCurrentInstance ( ) ) {
onServerPrefetch ( ( ) = > promise )
} else {
2023-10-16 19:54:39 +00:00
nuxt . hook ( 'app:created' , async ( ) = > { await promise } )
2022-12-10 22:44:29 +00:00
}
2021-10-08 14:21:55 +00:00
}
2021-04-03 10:03:20 +00:00
2021-10-08 14:21:55 +00:00
// Client side
2023-08-07 22:03:40 +00:00
if ( import . meta . client ) {
2022-08-30 10:48:26 +00:00
// Setup hook callbacks once per instance
const instance = getCurrentInstance ( )
2024-01-18 16:02:52 +00:00
if ( import . meta . dev && ! nuxt . isHydrating && ( ! instance || instance ? . isMounted ) ) {
// @ts-expect-error private property
console . warn ( ` [nuxt] [ ${ options . _functionName || 'useAsyncData' } ] Component is already mounted, please use $ fetch instead. See https://nuxt.com/docs/getting-started/data-fetching ` )
}
2022-08-30 10:48:26 +00:00
if ( instance && ! instance . _nuxtOnBeforeMountCbs ) {
instance . _nuxtOnBeforeMountCbs = [ ]
const cbs = instance . _nuxtOnBeforeMountCbs
if ( instance ) {
onBeforeMount ( ( ) = > {
cbs . forEach ( ( cb ) = > { cb ( ) } )
cbs . splice ( 0 , cbs . length )
} )
onUnmounted ( ( ) = > cbs . splice ( 0 , cbs . length ) )
}
}
2023-10-23 14:04:45 +00:00
if ( fetchOnServer && nuxt . isHydrating && ( asyncData . error . value || hasCachedData ( ) ) ) {
2021-11-24 19:59:04 +00:00
// 1. Hydration (server: true): no fetch
2021-10-08 14:21:55 +00:00
asyncData . pending . value = false
2023-06-09 21:38:14 +00:00
asyncData . status . value = asyncData . error . value ? 'error' : 'success'
2022-09-07 09:47:40 +00:00
} else if ( instance && ( ( nuxt . payload . serverRendered && nuxt . isHydrating ) || options . lazy ) && options . immediate ) {
2021-11-24 19:59:04 +00:00
// 2. Initial load (server: false): fetch on mounted
2022-08-24 19:05:28 +00:00
// 3. Initial load or navigation (lazy: true): fetch on mounted
2022-03-31 10:24:28 +00:00
instance . _nuxtOnBeforeMountCbs . push ( initialFetch )
2022-09-07 09:47:40 +00:00
} else if ( options . immediate ) {
2021-11-24 19:59:04 +00:00
// 4. Navigation (lazy: false) - or plugin usage: await fetch
2022-03-31 10:24:28 +00:00
initialFetch ( )
2021-01-18 12:46:19 +00:00
}
2022-03-16 22:49:30 +00:00
if ( options . watch ) {
2022-03-28 17:12:41 +00:00
watch ( options . watch , ( ) = > asyncData . refresh ( ) )
}
2023-10-16 19:54:39 +00:00
const off = nuxt . hook ( 'app:data:refresh' , async ( keys ) = > {
2022-03-28 17:12:41 +00:00
if ( ! keys || keys . includes ( key ) ) {
2023-10-16 19:54:39 +00:00
await asyncData . refresh ( )
2022-03-16 22:49:30 +00:00
}
2022-03-28 17:12:41 +00:00
} )
if ( instance ) {
onUnmounted ( off )
2022-03-16 22:49:30 +00:00
}
2021-01-18 12:46:19 +00:00
}
2021-03-01 09:45:37 +00:00
2021-10-08 14:21:55 +00:00
// Allow directly awaiting on asyncData
2023-12-14 12:41:40 +00:00
const asyncDataPromise = Promise . resolve ( nuxt . _asyncDataPromises [ key ] ) . then ( ( ) = > asyncData ) as AsyncData < ResT , ( NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError < NuxtErrorDataT > ) >
2021-10-08 14:21:55 +00:00
Object . assign ( asyncDataPromise , asyncData )
2023-12-14 12:41:40 +00:00
return asyncDataPromise as AsyncData < PickFrom < DataT , PickKeys > , ( NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError < NuxtErrorDataT > ) >
2021-10-11 22:36:50 +00:00
}
2024-01-19 17:03:30 +00:00
/** @since 3.0.0 */
2022-07-07 16:26:04 +00:00
export function useLazyAsyncData <
2023-03-11 22:36:10 +00:00
ResT ,
2022-07-07 16:26:04 +00:00
DataE = Error ,
2023-03-11 22:36:10 +00:00
DataT = ResT ,
2023-05-20 22:19:50 +00:00
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
DefaultT = null ,
2022-07-07 16:26:04 +00:00
> (
2023-03-11 22:36:10 +00:00
handler : ( ctx? : NuxtApp ) = > Promise < ResT > ,
2023-05-20 22:19:50 +00:00
options? : Omit < AsyncDataOptions < ResT , DataT , PickKeys , DefaultT > , 'lazy' >
) : AsyncData < PickFrom < DataT , PickKeys > | DefaultT , DataE | null >
2023-07-23 08:24:54 +00:00
export function useLazyAsyncData <
ResT ,
DataE = Error ,
DataT = ResT ,
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
DefaultT = DataT ,
> (
handler : ( ctx? : NuxtApp ) = > Promise < ResT > ,
options? : Omit < AsyncDataOptions < ResT , DataT , PickKeys , DefaultT > , 'lazy' >
) : AsyncData < PickFrom < DataT , PickKeys > | DefaultT , DataE | null >
2021-11-15 12:09:07 +00:00
export function useLazyAsyncData <
2023-03-11 22:36:10 +00:00
ResT ,
2022-04-29 18:42:22 +00:00
DataE = Error ,
2023-03-11 22:36:10 +00:00
DataT = ResT ,
2023-05-20 22:19:50 +00:00
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
DefaultT = null ,
2021-11-15 12:09:07 +00:00
> (
key : string ,
2023-03-11 22:36:10 +00:00
handler : ( ctx? : NuxtApp ) = > Promise < ResT > ,
2023-05-20 22:19:50 +00:00
options? : Omit < AsyncDataOptions < ResT , DataT , PickKeys , DefaultT > , 'lazy' >
) : AsyncData < PickFrom < DataT , PickKeys > | DefaultT , DataE | null >
2023-07-23 08:24:54 +00:00
export function useLazyAsyncData <
ResT ,
DataE = Error ,
DataT = ResT ,
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
DefaultT = DataT ,
> (
key : string ,
handler : ( ctx? : NuxtApp ) = > Promise < ResT > ,
options? : Omit < AsyncDataOptions < ResT , DataT , PickKeys , DefaultT > , 'lazy' >
) : AsyncData < PickFrom < DataT , PickKeys > | DefaultT , DataE | null >
2022-07-07 16:26:04 +00:00
export function useLazyAsyncData <
2023-03-11 22:36:10 +00:00
ResT ,
2022-07-07 16:26:04 +00:00
DataE = Error ,
2023-03-11 22:36:10 +00:00
DataT = ResT ,
2023-05-20 22:19:50 +00:00
PickKeys extends KeysOf < DataT > = KeysOf < DataT > ,
DefaultT = null ,
> ( . . . args : any [ ] ) : AsyncData < PickFrom < DataT , PickKeys > | DefaultT , DataE | null > {
2022-07-07 16:26:04 +00:00
const autoKey = typeof args [ args . length - 1 ] === 'string' ? args . pop ( ) : undefined
if ( typeof args [ 0 ] !== 'string' ) { args . unshift ( autoKey ) }
2024-01-18 16:02:52 +00:00
const [ key , handler , options = { } ] = args as [ string , ( ctx? : NuxtApp ) = > Promise < ResT > , AsyncDataOptions < ResT , DataT , PickKeys , DefaultT > ]
if ( import . meta . dev && import . meta . client ) {
// @ts-expect-error private property
options . _functionName || = 'useLazyAsyncData'
}
2023-04-14 12:53:21 +00:00
// @ts-expect-error we pass an extra argument to prevent a key being injected
2022-07-07 16:26:04 +00:00
return useAsyncData ( key , handler , { . . . options , lazy : true } , null )
2021-11-15 12:09:07 +00:00
}
2024-01-19 17:03:30 +00:00
/** @since 3.1.0 */
2022-12-05 13:07:33 +00:00
export function useNuxtData < DataT = any > ( key : string ) : { data : Ref < DataT | null > } {
const nuxt = useNuxtApp ( )
// Initialize value when key is not already set
if ( ! ( key in nuxt . payload . data ) ) {
nuxt . payload . data [ key ] = null
}
return {
data : toRef ( nuxt . payload . data , key )
}
}
2024-01-19 17:03:30 +00:00
/** @since 3.0.0 */
2022-10-25 15:29:35 +00:00
export async function refreshNuxtData ( keys? : string | string [ ] ) : Promise < void > {
2023-08-07 22:03:40 +00:00
if ( import . meta . server ) {
2022-03-28 17:12:41 +00:00
return Promise . resolve ( )
}
2023-05-22 23:09:05 +00:00
await new Promise < void > ( resolve = > onNuxtReady ( resolve ) )
2023-12-23 14:22:58 +00:00
const _keys = keys ? toArray ( keys ) : undefined
2022-10-25 15:29:35 +00:00
await useNuxtApp ( ) . hooks . callHookParallel ( 'app:data:refresh' , _keys )
2022-03-28 17:12:41 +00:00
}
2024-01-19 17:03:30 +00:00
/** @since 3.0.0 */
2022-09-07 13:25:37 +00:00
export function clearNuxtData ( keys? : string | string [ ] | ( ( key : string ) = > boolean ) ) : void {
2022-09-07 11:20:09 +00:00
const nuxtApp = useNuxtApp ( )
2022-09-07 13:25:37 +00:00
const _allKeys = Object . keys ( nuxtApp . payload . data )
const _keys : string [ ] = ! keys
? _allKeys
: typeof keys === 'function'
? _allKeys . filter ( keys )
2023-12-23 14:22:58 +00:00
: toArray ( keys )
2022-09-07 11:20:09 +00:00
for ( const key of _keys ) {
if ( key in nuxtApp . payload . data ) {
nuxtApp . payload . data [ key ] = undefined
}
if ( key in nuxtApp . payload . _errors ) {
2023-09-27 13:43:53 +00:00
nuxtApp . payload . _errors [ key ] = null
2022-09-07 11:20:09 +00:00
}
if ( nuxtApp . _asyncData [ key ] ) {
nuxtApp . _asyncData [ key ] ! . data . value = undefined
2023-09-27 13:43:53 +00:00
nuxtApp . _asyncData [ key ] ! . error . value = null
2022-09-07 11:20:09 +00:00
nuxtApp . _asyncData [ key ] ! . pending . value = false
2023-06-09 21:38:14 +00:00
nuxtApp . _asyncData [ key ] ! . status . value = 'idle'
2022-09-07 11:20:09 +00:00
}
if ( key in nuxtApp . _asyncDataPromises ) {
nuxtApp . _asyncDataPromises [ key ] = undefined
}
}
}
2021-10-11 22:36:50 +00:00
function pick ( obj : Record < string , any > , keys : string [ ] ) {
const newObj = { }
for ( const key of keys ) {
2022-08-12 17:47:58 +00:00
( newObj as any ) [ key ] = obj [ key ]
2021-10-11 22:36:50 +00:00
}
return newObj
2021-03-01 09:45:37 +00:00
}