feat(nuxt): respect defaults when clearing asyncData (#27295)

This commit is contained in:
Daniel Roe 2024-05-22 15:42:19 +01:00 committed by GitHub
parent 305c7348bd
commit 811bfc18a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 49 additions and 4 deletions

View File

@ -48,6 +48,7 @@ export default defineNuxtConfig({
// experimental: {
// sharedPrerenderData: false,
// compileTemplate: true,
// resetAsyncDataToUndefined: true,
// templateUtils: true,
// relativeWatchPaths: true,
// defaults: {
@ -220,6 +221,32 @@ export default defineNuxtConfig({
Please report an issue if you are doing this, as we do not plan to keep this as configurable.
#### Respect defaults when clearing `data` in `useAsyncData` and `useFetch`
🚦 **Impact Level**: Minimal
##### What Changed
If you provide a custom `default` value for `useAsyncData`, this will now be used when calling `clear` or `clearNuxtData` and it will be reset to its default value rather than simply unset.
##### Reasons for Change
Often users set an appropriately empty value, such as an empty array, to avoid the need to check for `null`/`undefined` when iterating over it. This should be respected when resetting/clearing the data.
##### Migration Steps
If you encounter any issues you can revert back to the previous behavior, for now, with:
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
resetAsyncDataToUndefined: true,
}
})
```
Please report an issue if you are doing so, as we do not plan to keep this as configurable.
#### Shallow Data Reactivity in `useAsyncData` and `useFetch`
🚦 **Impact Level**: Minimal

View File

@ -8,7 +8,7 @@ import { createError } from './error'
import { onNuxtReady } from './ready'
// @ts-expect-error virtual file
import { asyncDataDefaults } from '#build/nuxt.config.mjs'
import { asyncDataDefaults, resetAsyncDataToUndefined } from '#build/nuxt.config.mjs'
// TODO: temporary module for backwards compatibility
import type { DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults'
@ -267,11 +267,15 @@ export function useAsyncData<
pending: ref(!hasCachedData()),
error: toRef(nuxtApp.payload._errors, key),
status: ref('idle'),
_default: options.default!,
}
}
// TODO: Else, somehow check for conflicting keys with different defaults or fetcher
const asyncData = { ...nuxtApp._asyncData[key] } as AsyncData<DataT | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>)>
const asyncData = { ...nuxtApp._asyncData[key] } as { _default?: unknown } & AsyncData<DataT | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>)>
// Don't expose default function to end user
delete asyncData._default
asyncData.refresh = asyncData.execute = (opts = {}) => {
if (nuxtApp._asyncDataPromises[key]) {
@ -528,7 +532,7 @@ function clearNuxtDataByKey (nuxtApp: NuxtApp, key: string): void {
}
if (nuxtApp._asyncData[key]) {
nuxtApp._asyncData[key]!.data.value = undefined
nuxtApp._asyncData[key]!.data.value = resetAsyncDataToUndefined ? undefined : nuxtApp._asyncData[key]!._default()
nuxtApp._asyncData[key]!.error.value = asyncDataDefaults.errorValue
nuxtApp._asyncData[key]!.pending.value = false
nuxtApp._asyncData[key]!.status.value = 'idle'

View File

@ -122,10 +122,12 @@ interface _NuxtApp {
_asyncDataPromises: Record<string, Promise<any> | undefined>
/** @internal */
_asyncData: Record<string, {
data: Ref<any>
data: Ref<unknown>
pending: Ref<boolean>
error: Ref<Error | DefaultAsyncDataErrorValue>
status: Ref<AsyncDataRequestStatus>
/** @internal */
_default: () => unknown
} | undefined>
/** @internal */

View File

@ -404,6 +404,7 @@ export const nuxtConfigTemplate: NuxtTemplate = {
value: ctx.nuxt.options.experimental.defaults.useAsyncData.value === 'null' ? null : undefined,
errorValue: ctx.nuxt.options.experimental.defaults.useAsyncData.errorValue === 'null' ? null : undefined,
})}`,
`export const resetAsyncDataToUndefined = ${ctx.nuxt.options.experimental.resetAsyncDataToUndefined}`,
`export const nuxtDefaultErrorValue = ${ctx.nuxt.options.future.compatibilityVersion === 4 ? 'undefined' : 'null'}`,
`export const fetchDefaults = ${JSON.stringify(fetchDefaults)}`,
`export const vueAppRootContainer = ${ctx.nuxt.options.app.rootId ? `'#${ctx.nuxt.options.app.rootId}'` : `'body > ${ctx.nuxt.options.app.rootTag}'`}`,

View File

@ -29,6 +29,7 @@ export default defineUntypedSchema({
* compileTemplate: true,
* templateUtils: true,
* relativeWatchPaths: true,
* resetAsyncDataToUndefined: true,
* defaults: {
* useAsyncData: {
* deep: true
@ -488,5 +489,15 @@ export default defineUntypedSchema({
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion !== 4)
},
},
/**
* Whether `clear` and `clearNuxtData` should reset async data to its _default_ value or update
* it to `null`/`undefined`.
*/
resetAsyncDataToUndefined: {
async $resolve (val, get) {
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion !== 4)
},
},
},
})