Skip to content

Commit

Permalink
fix: Ensure that using preload with useSWRInfinite returns back an ar…
Browse files Browse the repository at this point in the history
…ray of data (#2726)

* Fix the preload function for useSWRInfinite

* fix missing import

* Update _internal/src/utils/preload.ts

* Fix the issue where preloaded pages were not returned back as a array

---------

Co-authored-by: Shu Ding <[email protected]>
  • Loading branch information
agadzik and shuding authored Jul 26, 2023
1 parent d14cef2 commit c64a8bd
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 7 deletions.
9 changes: 5 additions & 4 deletions _internal/src/utils/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
23 changes: 20 additions & 3 deletions infinite/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -63,6 +66,7 @@ export const infinite = (<Data, Error>(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.
Expand All @@ -73,6 +77,7 @@ export const infinite = (<Data, Error>(useSWRNext: SWRHook) =>
} catch (err) {
// Not ready yet.
}

const [get, set, subscribeCache] = createCacheHelper<
Data,
SWRInfiniteCacheValue<Data, any>
Expand Down Expand Up @@ -164,9 +169,22 @@ export const infinite = (<Data, Error>(useSWRNext: SWRHook) =>
SWRInfiniteCacheValue<Data, any>
>(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
Expand All @@ -183,7 +201,6 @@ export const infinite = (<Data, Error>(useSWRNext: SWRHook) =>
(cacheData &&
!isUndefined(cacheData[i]) &&
!config.compare(cacheData[i], pageData))

if (fn && shouldFetchPage) {
const revalidate = async () => {
pageData = await fn(pageArg)
Expand Down
15 changes: 15 additions & 0 deletions test/use-swr-infinite-preload.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <div>data:{Array.isArray(data) ? 'true' : 'false'}</div>
}

preload(getKey(0), fetcher)
renderWithConfig(<Page />)
await screen.findByText('data:true')
})

it('preload the fetcher function', async () => {
const key = createKey()
const getKey = getKeyFunction(key)
Expand Down
2 changes: 2 additions & 0 deletions test/use-swr-infinite.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('useSWRInfinite', () => {
return (
<div>
<div>data:{data}</div>
<div>isArray:{Array.isArray(data) ? 'true' : 'false'}</div>
<div>error:{error}</div>
<div>isValidating:{isValidating.toString()}</div>
</div>
Expand All @@ -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`)
})
Expand Down

0 comments on commit c64a8bd

Please sign in to comment.