feat(nuxt): add `clear` utility to `useAsyncData`/`useFetch` (#26259)

This commit is contained in:
Damian Głowala 2024-03-17 01:19:44 +01:00 committed by GitHub
parent 3c7e68c846
commit 02d6838293
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 45 additions and 17 deletions

View File

@ -150,6 +150,7 @@ Read more about `useAsyncData`.
- `data`: the result of the asynchronous function that is passed in.
- `pending`: a boolean indicating whether the data is still being fetched.
- `refresh`/`execute`: a function that can be used to refresh the data returned by the `handler` function.
- `clear`: a function that can be used to set `data` to undefined, set `error` to `null`, set `pending` to `false`, set `status` to `idle`, and mark any currently pending requests as cancelled.
- `error`: an error object if the data fetching failed.
- `status`: a string indicating the status of the data request (`"idle"`, `"pending"`, `"success"`, `"error"`).

View File

@ -130,6 +130,7 @@ type AsyncData<DataT, ErrorT> = {
pending: Ref<boolean>
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
clear: () => void
error: Ref<ErrorT | null>
status: Ref<AsyncDataRequestStatus>
};

View File

@ -158,6 +158,7 @@ type AsyncData<DataT, ErrorT> = {
pending: Ref<boolean>
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
clear: () => void
error: Ref<ErrorT | null>
status: Ref<AsyncDataRequestStatus>
}

View File

@ -111,6 +111,7 @@ export interface _AsyncData<DataT, ErrorT> {
pending: Ref<boolean>
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
clear: () => void
error: Ref<ErrorT | null>
status: Ref<AsyncDataRequestStatus>
}
@ -221,8 +222,9 @@ export function useAsyncData<
if (value) { return value as Promise<ResT> }
const promise = nuxtApp.runWithContext(_handler)
nuxtApp.ssrContext!._sharedPrerenderCache!.set(key, promise)
return promise
nuxtApp.ssrContext!._sharedPrerenderCache!.set(key, promise)
return promise
}
// Used to get default values
@ -322,6 +324,8 @@ export function useAsyncData<
return nuxtApp._asyncDataPromises[key]!
}
asyncData.clear = () => clearNuxtDataByKey(nuxtApp, key)
const initialFetch = () => asyncData.refresh({ _initial: true })
const fetchOnServer = options.server !== false && nuxtApp.payload.serverRendered
@ -499,21 +503,29 @@ export function clearNuxtData (keys?: string | string[] | ((key: string) => bool
: toArray(keys)
for (const key of _keys) {
if (key in nuxtApp.payload.data) {
nuxtApp.payload.data[key] = undefined
}
if (key in nuxtApp.payload._errors) {
nuxtApp.payload._errors[key] = null
}
if (nuxtApp._asyncData[key]) {
nuxtApp._asyncData[key]!.data.value = undefined
nuxtApp._asyncData[key]!.error.value = null
nuxtApp._asyncData[key]!.pending.value = false
nuxtApp._asyncData[key]!.status.value = 'idle'
}
if (key in nuxtApp._asyncDataPromises) {
nuxtApp._asyncDataPromises[key] = undefined
}
clearNuxtDataByKey(nuxtApp, key)
}
}
function clearNuxtDataByKey (nuxtApp: NuxtApp, key: string): void {
if (key in nuxtApp.payload.data) {
nuxtApp.payload.data[key] = undefined
}
if (key in nuxtApp.payload._errors) {
nuxtApp.payload._errors[key] = null
}
if (nuxtApp._asyncData[key]) {
nuxtApp._asyncData[key]!.data.value = undefined
nuxtApp._asyncData[key]!.error.value = null
nuxtApp._asyncData[key]!.pending.value = false
nuxtApp._asyncData[key]!.status.value = 'idle'
}
if (key in nuxtApp._asyncDataPromises) {
(nuxtApp._asyncDataPromises[key] as any).cancelled = true
nuxtApp._asyncDataPromises[key] = undefined
}
}

View File

@ -123,6 +123,7 @@ describe('useAsyncData', () => {
"status",
"execute",
"refresh",
"clear",
]
`)
expect(res instanceof Promise).toBeTruthy()
@ -200,6 +201,18 @@ describe('useAsyncData', () => {
expect(data.data.value).toMatchInlineSnapshot('"test"')
})
it('should be clearable', async () => {
const { data, error, pending, status, clear } = await useAsyncData(() => Promise.resolve('test'))
expect(data.value).toBe('test')
clear()
expect(data.value).toBeUndefined()
expect(error.value).toBeNull()
expect(pending.value).toBe(false)
expect(status.value).toBe('idle')
})
it('allows custom access to a cache', async () => {
const { data } = await useAsyncData(() => ({ val: true }), { getCachedData: () => ({ val: false }) })
expect(data.value).toMatchInlineSnapshot(`