Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Ensure that using preload with useSWRInfinite returns back an array of data #2726

Merged
merged 5 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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