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

Add isFallback state #1925

Merged
merged 3 commits into from Apr 15, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 6 additions & 3 deletions infinite/index.ts
Expand Up @@ -258,14 +258,17 @@ export const infinite = (<Data, Error>(useSWRNext: SWRHook) =>
size: resolvePageSize(),
setSize,
mutate,
get error() {
return swr.error
},
get data() {
return swr.data
},
get error() {
return swr.error
},
get isValidating() {
return swr.isValidating
},
get isFallback() {
return swr.isFallback
}
} as SWRInfiniteResponse<Data, Error>
}) as unknown as Middleware
Expand Down
5 changes: 3 additions & 2 deletions src/types.ts
Expand Up @@ -216,10 +216,11 @@ export type SWRConfiguration<
> = Partial<PublicConfiguration<Data, Error, Fn>>

export interface SWRResponse<Data = any, Error = any> {
data?: Data
error?: Error
data: Data | undefined
error: Error | undefined
mutate: KeyedMutator<Data>
isValidating: boolean
isFallback: boolean
}

export type KeyLoader<Args extends Arguments = Arguments> =
Expand Down
40 changes: 27 additions & 13 deletions src/use-swr.ts
Expand Up @@ -307,30 +307,38 @@ export const useSWRHandler = <Data = any, Error = any>(
} catch (err) {
cleanupState()

const currentConfig = getConfig()
const { shouldRetryOnError } = currentConfig

// Not paused, we continue handling the error. Otherwise discard it.
if (!getConfig().isPaused()) {
if (!currentConfig.isPaused()) {
// Get a new error, don't use deep comparison for errors.
set({ error: err })
newState.error = err as Error

// Error event and retry logic. Only for the actual request, not
// deduped ones.
if (shouldStartNewRequest && isCurrentKeyMounted()) {
getConfig().onError(err, key, config)
currentConfig.onError(err, key, currentConfig)
if (
(typeof config.shouldRetryOnError === 'boolean' &&
config.shouldRetryOnError) ||
(isFunction(config.shouldRetryOnError) &&
config.shouldRetryOnError(err as Error))
shouldRetryOnError === true ||
(isFunction(shouldRetryOnError) &&
shouldRetryOnError(err as Error))
) {
// When retrying, dedupe is always enabled
if (isActive()) {
// If it's active, stop. It will auto revalidate when refocusing
// or reconnecting.
getConfig().onErrorRetry(err, key, config, revalidate, {
retryCount: (opts.retryCount || 0) + 1,
dedupe: true
})
// If it's inactive, stop. It will auto revalidate when
// refocusing or reconnecting.
// When retrying, deduplication is always enabled.
currentConfig.onErrorRetry(
err,
key,
currentConfig,
revalidate,
{
retryCount: (opts.retryCount || 0) + 1,
dedupe: true
}
)
}
}
}
Expand Down Expand Up @@ -546,6 +554,12 @@ export const useSWRHandler = <Data = any, Error = any>(
get isValidating() {
stateDependencies.isValidating = true
return isValidating
},
get isFallback() {
stateDependencies.data = true
// `isFallback` is only true when we are displaying a value other than
// the cached one.
return data !== cachedData
}
} as SWRResponse<Data, Error>
}
Expand Down
12 changes: 8 additions & 4 deletions test/use-swr-cache.test.tsx
Expand Up @@ -198,19 +198,23 @@ describe('useSWR - cache provider', () => {
it('should support fallback values with custom provider', async () => {
const key = createKey()
function Page() {
const { data } = useSWR(key, async () => {
const { data, isFallback } = useSWR(key, async () => {
await sleep(10)
return 'data'
})
return <>{String(data)}</>
return (
<>
{String(data)},{String(isFallback)}
</>
)
}

renderWithConfig(<Page />, {
provider: () => provider,
fallback: { [key]: 'fallback' }
})
screen.getByText('fallback') // no `undefined`, directly fallback
await screen.findByText('data')
screen.getByText('fallback,true') // no `undefined`, directly fallback
await screen.findByText('data,false')
})

it('should not return the fallback if cached', async () => {
Expand Down
2 changes: 1 addition & 1 deletion test/use-swr-loading.test.tsx
Expand Up @@ -138,7 +138,7 @@ describe('useSWR - loading', () => {
}

renderWithConfig(<Page />)
screen.getByText('data,error,isValidating,mutate')
screen.getByText('data,error,isFallback,isValidating,mutate')
})

it('should sync loading states', async () => {
Expand Down