diff --git a/_internal/src/utils/preload.ts b/_internal/src/utils/preload.ts index 75e69d716..e5d47642a 100644 --- a/_internal/src/utils/preload.ts +++ b/_internal/src/utils/preload.ts @@ -48,14 +48,15 @@ export const middleware: Middleware = const [key] = serialize(key_) const [, , , PRELOAD] = SWRGlobalState.get(cache) as GlobalState - let normalizedKey = key if (key.startsWith(INFINITE_PREFIX)) { - normalizedKey = key.slice(INFINITE_PREFIX.length) + // we want the infinite fetcher to be called. + // handling of the PRELOAD cache happens there. + return fetcher_(...args) } - const req = PRELOAD[normalizedKey] + const req = PRELOAD[key] if (isUndefined(req)) return fetcher_(...args) - delete PRELOAD[normalizedKey] + delete PRELOAD[key] return req }) return useSWRNext(key_, fetcher, config) diff --git a/infinite/src/index.ts b/infinite/src/index.ts index 7fd4b6ff5..2b41b1c78 100644 --- a/infinite/src/index.ts +++ b/infinite/src/index.ts @@ -12,14 +12,17 @@ import { useIsomorphicLayoutEffect, serialize, withMiddleware, - INFINITE_PREFIX + INFINITE_PREFIX, + SWRGlobalState, + cache as defaultCache } from 'swr/_internal' import type { BareFetcher, SWRHook, MutatorCallback, Middleware, - MutatorOptions + MutatorOptions, + GlobalState } from 'swr/_internal' import type { SWRInfiniteConfiguration, @@ -63,6 +66,7 @@ export const infinite = ((useSWRNext: SWRHook) => revalidateOnMount = false, parallel = false } = config + const [, , , PRELOAD] = SWRGlobalState.get(defaultCache) as GlobalState // The serialized key of the first page. This key will be used to store // metadata of this SWR infinite hook. @@ -73,6 +77,7 @@ export const infinite = ((useSWRNext: SWRHook) => } catch (err) { // Not ready yet. } + const [get, set, subscribeCache] = createCacheHelper< Data, SWRInfiniteCacheValue @@ -164,9 +169,22 @@ export const infinite = ((useSWRNext: SWRHook) => SWRInfiniteCacheValue >(cache, pageKey) + const hasPreloadedRequest = pageKey in PRELOAD // Get the cached page data. let pageData = getSWRCache().data as Data + if (hasPreloadedRequest) { + const req = PRELOAD[pageKey] + // delete the preload cache key before resolving it + // in case there's an error + delete PRELOAD[pageKey] + // get the page data from the preload cache + pageData = await req + // set the SWR cache with the preloaded data + setSWRCache({ data: pageData, _k: pageArg }) + // remove the preload cache key to prevent memory leak + } + // should fetch (or revalidate) if: // - `revalidateAll` is enabled // - `mutate()` called @@ -183,7 +201,6 @@ export const infinite = ((useSWRNext: SWRHook) => (cacheData && !isUndefined(cacheData[i]) && !config.compare(cacheData[i], pageData)) - if (fn && shouldFetchPage) { const revalidate = async () => { pageData = await fn(pageArg) diff --git a/test/use-swr-infinite-preload.test.tsx b/test/use-swr-infinite-preload.test.tsx index b47508380..c25d8fbc3 100644 --- a/test/use-swr-infinite-preload.test.tsx +++ b/test/use-swr-infinite-preload.test.tsx @@ -8,6 +8,21 @@ describe('useSWRInfinite - preload', () => { const getKeyFunction = (key: string) => (index: number) => `page-${index}-${key}` + it('preloading useSWRInfinite should produce the same result', async () => { + const key = createKey() + const getKey = getKeyFunction(key) + + const fetcher = jest.fn(() => createResponse('foo')) + function Page() { + const { data } = useSWRInfinite(getKey, fetcher) + return
data:{Array.isArray(data) ? 'true' : 'false'}
+ } + + preload(getKey(0), fetcher) + renderWithConfig() + await screen.findByText('data:true') + }) + it('preload the fetcher function', async () => { const key = createKey() const getKey = getKeyFunction(key) diff --git a/test/use-swr-infinite.test.tsx b/test/use-swr-infinite.test.tsx index 30a287580..18678550c 100644 --- a/test/use-swr-infinite.test.tsx +++ b/test/use-swr-infinite.test.tsx @@ -24,6 +24,7 @@ describe('useSWRInfinite', () => { return (
data:{data}
+
isArray:{Array.isArray(data) ? 'true' : 'false'}
error:{error}
isValidating:{isValidating.toString()}
@@ -34,6 +35,7 @@ describe('useSWRInfinite', () => { screen.getByText('data:') await screen.findByText(`data:page-0-${key}`) + await screen.findByText(`isArray:true`) await screen.findByText(`error:`) await screen.findByText(`isValidating:false`) })