Skip to content

Commit

Permalink
feat(nuxt): add clear utility to useAsyncData/useFetch (#26259)
Browse files Browse the repository at this point in the history
  • Loading branch information
DamianGlowala committed Mar 17, 2024
1 parent 3c7e68c commit 02d6838
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 17 deletions.
1 change: 1 addition & 0 deletions docs/1.getting-started/6.data-fetching.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"`).

Expand Down
1 change: 1 addition & 0 deletions docs/3.api/2.composables/use-async-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>
};
Expand Down
1 change: 1 addition & 0 deletions docs/3.api/2.composables/use-fetch.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>
}
Expand Down
46 changes: 29 additions & 17 deletions packages/nuxt/src/app/composables/asyncData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
}

Expand Down
13 changes: 13 additions & 0 deletions test/nuxt/composables.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ describe('useAsyncData', () => {
"status",
"execute",
"refresh",
"clear",
]
`)
expect(res instanceof Promise).toBeTruthy()
Expand Down Expand Up @@ -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(`
Expand Down

0 comments on commit 02d6838

Please sign in to comment.