diff --git a/packages/nuxt/src/app/composables/asyncData.ts b/packages/nuxt/src/app/composables/asyncData.ts index 40ab34494a1..1bd3d2133c2 100644 --- a/packages/nuxt/src/app/composables/asyncData.ts +++ b/packages/nuxt/src/app/composables/asyncData.ts @@ -85,12 +85,20 @@ export function useAsyncData< const useInitialCache = () => options.initialCache && nuxt.payload.data[key] !== undefined - const asyncData = { + let asyncData = { data: wrapInRef(nuxt.payload.data[key] ?? options.default()), pending: ref(!useInitialCache()), error: ref(nuxt.payload._errors[key] ?? null) } as AsyncData + // If this query is pending, grab async data from store + // Otherwise, set our async data + if (nuxt._asyncDataPromises[key]) { + asyncData = nuxt._pendingAsyncData[key] + } else { + nuxt._pendingAsyncData[key] = asyncData + } + asyncData.refresh = (opts = {}) => { // Avoid fetching same key more than once at a time if (nuxt._asyncDataPromises[key]) { @@ -98,6 +106,9 @@ export function useAsyncData< } // Avoid fetching same key that is already fetched if (opts._initial && useInitialCache()) { + // Prevent memory leak, no promise to resolve so key is never deleted + delete nuxt._pendingAsyncData[key] + return nuxt.payload.data[key] } asyncData.pending.value = true @@ -125,6 +136,7 @@ export function useAsyncData< nuxt.payload._errors[key] = true } delete nuxt._asyncDataPromises[key] + delete nuxt._pendingAsyncData[key] }) return nuxt._asyncDataPromises[key] } @@ -167,6 +179,7 @@ export function useAsyncData< // Allow directly awaiting on asyncData const asyncDataPromise = Promise.resolve(nuxt._asyncDataPromises[key]).then(() => asyncData) as AsyncData + Object.assign(asyncDataPromise, asyncData) return asyncDataPromise as AsyncData, PickKeys>, DataE> diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts index 65d50a560b0..ff197e63d1b 100644 --- a/packages/nuxt/src/app/nuxt.ts +++ b/packages/nuxt/src/app/nuxt.ts @@ -5,6 +5,7 @@ import { createHooks, Hookable } from 'hookable' import type { RuntimeConfig } from '@nuxt/schema' import { getContext } from 'unctx' import { legacyPlugin, LegacyContext } from './compat/legacy-app' +import { AsyncData } from './composables/asyncData' const nuxtAppCtx = getContext('nuxt-app') @@ -46,6 +47,7 @@ interface _NuxtApp { [key: string]: any _asyncDataPromises?: Record> + _pendingAsyncData?: Record> _legacyContext?: LegacyContext ssrContext?: Record & { @@ -91,6 +93,7 @@ export function createNuxtApp (options: CreateOptions) { }), isHydrating: process.client, _asyncDataPromises: {}, + _pendingAsyncData: {}, ...options } as any as NuxtApp