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

feat: refreshInterval as a function #1690

Merged
merged 1 commit into from
Dec 4, 2021
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
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface PublicConfiguration<
loadingTimeout: number
focusThrottleInterval: number
dedupingInterval: number
refreshInterval?: number
refreshInterval?: number | ((latestData: Data | undefined) => number)
refreshWhenHidden?: boolean
refreshWhenOffline?: boolean
revalidateOnFocus: boolean
Expand Down
18 changes: 15 additions & 3 deletions src/use-swr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { defaultConfig } from './utils/config'
import { SWRGlobalState, GlobalState } from './utils/global-state'
import { IS_SERVER, rAF, useIsomorphicLayoutEffect } from './utils/env'
import { serialize } from './utils/serialize'
import { isUndefined, UNDEFINED, OBJECT, mergeObjects } from './utils/helper'
import {
isUndefined,
UNDEFINED,
OBJECT,
mergeObjects,
isFunction
} from './utils/helper'
import ConfigProvider from './utils/config-context'
import { useStateWithDeps } from './utils/state'
import { withArgs } from './utils/resolve-args'
Expand Down Expand Up @@ -440,11 +446,17 @@ export const useSWRHandler = <Data = any, Error = any>(
let timer: any

function next() {
// Use the passed interval
// ...or invoke the function with the updated data to get the interval
const interval = isFunction(refreshInterval)
? refreshInterval(data)
: refreshInterval

// We only start next interval if `refreshInterval` is not 0, and:
// - `force` is true, which is the start of polling
// - or `timer` is not 0, which means the effect wasn't canceled
if (refreshInterval && timer !== -1) {
timer = setTimeout(execute, refreshInterval)
if (interval && timer !== -1) {
timer = setTimeout(execute, interval)
Andrewnt219 marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
60 changes: 60 additions & 0 deletions test/use-swr-refresh.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -374,4 +374,64 @@ describe('useSWR - refresh', () => {
expect(fetcherWithToken).toBeCalledTimes(5)
expect(fetcherWithToken).toHaveBeenLastCalledWith(`1-${key}`)
})

it('should allow using function as an interval', async () => {
let count = 0

const key = createKey()
function Page() {
const { data } = useSWR(key, () => count++, {
refreshInterval: () => 200,
dedupingInterval: 100
})
return <div>count: {data}</div>
}

renderWithConfig(<Page />)

// hydration
screen.getByText('count:')

// mount
await screen.findByText('count: 0')

await act(() => advanceTimers(200)) // update
screen.getByText('count: 1')
await act(() => advanceTimers(50)) // no update
screen.getByText('count: 1')
await act(() => advanceTimers(150)) // update
screen.getByText('count: 2')
})

it('should pass updated data to refreshInterval', async () => {
let count = 1

const key = createKey()
function Page() {
const { data } = useSWR(key, () => count++, {
refreshInterval: updatedCount => updatedCount * 1000,
dedupingInterval: 100
})
return <div>count: {data}</div>
}

renderWithConfig(<Page />)

// hydration
screen.getByText('count:')

// mount
await screen.findByText('count: 1')

await act(() => advanceTimers(1000)) // updated after 1s
screen.getByText('count: 2')
await act(() => advanceTimers(1000)) // no update
screen.getByText('count: 2')
await act(() => advanceTimers(1000)) // updated after 2s
screen.getByText('count: 3')
await act(() => advanceTimers(2000)) // no update
screen.getByText('count: 3')
await act(() => advanceTimers(1000)) // updated after 3s
screen.getByText('count: 4')
})
})