mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 21:55:11 +00:00
feat(nuxt): warn if data fetch composables are used wrongly (#25071)
This commit is contained in:
parent
12ec76618d
commit
951ffd6e01
@ -42,15 +42,51 @@ export interface AsyncDataOptions<
|
|||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = null,
|
DefaultT = null,
|
||||||
> {
|
> {
|
||||||
|
/**
|
||||||
|
* Whether to fetch on the server side.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
server?: boolean
|
server?: boolean
|
||||||
|
/**
|
||||||
|
* Whether to resolve the async function after loading the route, instead of blocking client-side navigation
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
lazy?: boolean
|
lazy?: boolean
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
default?: () => DefaultT | Ref<DefaultT>
|
default?: () => DefaultT | Ref<DefaultT>
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
getCachedData?: (key: string) => DataT
|
getCachedData?: (key: string) => DataT
|
||||||
|
/**
|
||||||
|
* A function that can be used to alter handler function result after resolving
|
||||||
|
*/
|
||||||
transform?: _Transform<ResT, DataT>
|
transform?: _Transform<ResT, DataT>
|
||||||
|
/**
|
||||||
|
* Only pick specified keys in this array from the handler function result
|
||||||
|
*/
|
||||||
pick?: PickKeys
|
pick?: PickKeys
|
||||||
|
/**
|
||||||
|
* Watch reactive sources to auto-refresh when changed
|
||||||
|
*/
|
||||||
watch?: MultiWatchSources
|
watch?: MultiWatchSources
|
||||||
|
/**
|
||||||
|
* When set to false, will prevent the request from firing immediately
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
immediate?: boolean
|
immediate?: boolean
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
deep?: boolean
|
deep?: boolean
|
||||||
|
/**
|
||||||
|
* Avoid fetching the same key more than once at a time
|
||||||
|
* @default 'cancel'
|
||||||
|
*/
|
||||||
dedupe?: 'cancel' | 'defer'
|
dedupe?: 'cancel' | 'defer'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +118,12 @@ export type AsyncData<Data, Error> = _AsyncData<Data, Error> & Promise<_AsyncDat
|
|||||||
// TODO: deprecate boolean option in future minor
|
// TODO: deprecate boolean option in future minor
|
||||||
const isDefer = (dedupe?: boolean | 'cancel' | 'defer') => dedupe === 'defer' || dedupe === false
|
const isDefer = (dedupe?: boolean | 'cancel' | 'defer') => dedupe === 'defer' || dedupe === false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
export function useAsyncData<
|
export function useAsyncData<
|
||||||
ResT,
|
ResT,
|
||||||
NuxtErrorDataT = unknown,
|
NuxtErrorDataT = unknown,
|
||||||
@ -92,6 +134,12 @@ export function useAsyncData<
|
|||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null>
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
export function useAsyncData<
|
export function useAsyncData<
|
||||||
ResT,
|
ResT,
|
||||||
NuxtErrorDataT = unknown,
|
NuxtErrorDataT = unknown,
|
||||||
@ -102,6 +150,13 @@ export function useAsyncData<
|
|||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null>
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
export function useAsyncData<
|
export function useAsyncData<
|
||||||
ResT,
|
ResT,
|
||||||
NuxtErrorDataT = unknown,
|
NuxtErrorDataT = unknown,
|
||||||
@ -113,6 +168,13 @@ export function useAsyncData<
|
|||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null>
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
export function useAsyncData<
|
export function useAsyncData<
|
||||||
ResT,
|
ResT,
|
||||||
NuxtErrorDataT = unknown,
|
NuxtErrorDataT = unknown,
|
||||||
@ -269,6 +331,10 @@ export function useAsyncData<
|
|||||||
if (import.meta.client) {
|
if (import.meta.client) {
|
||||||
// Setup hook callbacks once per instance
|
// Setup hook callbacks once per instance
|
||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
|
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`)
|
||||||
|
}
|
||||||
if (instance && !instance._nuxtOnBeforeMountCbs) {
|
if (instance && !instance._nuxtOnBeforeMountCbs) {
|
||||||
instance._nuxtOnBeforeMountCbs = []
|
instance._nuxtOnBeforeMountCbs = []
|
||||||
const cbs = instance._nuxtOnBeforeMountCbs
|
const cbs = instance._nuxtOnBeforeMountCbs
|
||||||
@ -364,7 +430,13 @@ export function useLazyAsyncData<
|
|||||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null> {
|
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null> {
|
||||||
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
||||||
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
||||||
const [key, handler, options] = args as [string, (ctx?: NuxtApp) => Promise<ResT>, AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>]
|
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'
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-expect-error we pass an extra argument to prevent a key being injected
|
// @ts-expect-error we pass an extra argument to prevent a key being injected
|
||||||
return useAsyncData(key, handler, { ...options, lazy: true }, null)
|
return useAsyncData(key, handler, { ...options, lazy: true }, null)
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,12 @@ export interface UseFetchOptions<
|
|||||||
watch?: MultiWatchSources | false
|
watch?: MultiWatchSources | false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch data from an API endpoint with an SSR-friendly composable.
|
||||||
|
* See {@link https://nuxt.com/docs/api/composables/use-fetch}
|
||||||
|
* @param request The URL to fetch
|
||||||
|
* @param opts extends $fetch options and useAsyncData options
|
||||||
|
*/
|
||||||
export function useFetch<
|
export function useFetch<
|
||||||
ResT = void,
|
ResT = void,
|
||||||
ErrorT = FetchError,
|
ErrorT = FetchError,
|
||||||
@ -52,6 +58,12 @@ export function useFetch<
|
|||||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||||
opts?: UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>
|
opts?: UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | null>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | null>
|
||||||
|
/**
|
||||||
|
* Fetch data from an API endpoint with an SSR-friendly composable.
|
||||||
|
* See {@link https://nuxt.com/docs/api/composables/use-fetch}
|
||||||
|
* @param request The URL to fetch
|
||||||
|
* @param opts extends $fetch options and useAsyncData options
|
||||||
|
*/
|
||||||
export function useFetch<
|
export function useFetch<
|
||||||
ResT = void,
|
ResT = void,
|
||||||
ErrorT = FetchError,
|
ErrorT = FetchError,
|
||||||
@ -134,6 +146,11 @@ export function useFetch<
|
|||||||
watch: watch === false ? [] : [_fetchOptions, _request, ...(watch || [])]
|
watch: watch === false ? [] : [_fetchOptions, _request, ...(watch || [])]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (import.meta.dev && import.meta.client) {
|
||||||
|
// @ts-expect-error private property
|
||||||
|
_asyncDataOptions._functionName = opts._functionName || 'useFetch'
|
||||||
|
}
|
||||||
|
|
||||||
let controller: AbortController
|
let controller: AbortController
|
||||||
|
|
||||||
const asyncData = useAsyncData<_ResT, ErrorT, DataT, PickKeys, DefaultT>(key, () => {
|
const asyncData = useAsyncData<_ResT, ErrorT, DataT, PickKeys, DefaultT>(key, () => {
|
||||||
@ -207,7 +224,12 @@ export function useLazyFetch<
|
|||||||
arg1?: string | Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>,
|
arg1?: string | Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>,
|
||||||
arg2?: string
|
arg2?: string
|
||||||
) {
|
) {
|
||||||
const [opts, autoKey] = typeof arg1 === 'string' ? [{}, arg1] : [arg1, arg2]
|
const [opts = {}, autoKey] = typeof arg1 === 'string' ? [{}, arg1] : [arg1, arg2]
|
||||||
|
|
||||||
|
if (import.meta.dev && import.meta.client) {
|
||||||
|
// @ts-expect-error private property
|
||||||
|
opts._functionName ||= 'useLazyFetch'
|
||||||
|
}
|
||||||
|
|
||||||
return useFetch<ResT, ErrorT, ReqT, Method, _ResT, DataT, PickKeys, DefaultT>(request, {
|
return useFetch<ResT, ErrorT, ReqT, Method, _ResT, DataT, PickKeys, DefaultT>(request, {
|
||||||
...opts,
|
...opts,
|
||||||
|
Loading…
Reference in New Issue
Block a user