Skip to content

Commit 4663154

Browse files
authored
feat: refreshInterval as a function (#1690)
* allow passing a function that returns a new interval for refreshInterval * add tests for refreshInterval as a function
1 parent 16778a7 commit 4663154

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export interface PublicConfiguration<
3535
loadingTimeout: number
3636
focusThrottleInterval: number
3737
dedupingInterval: number
38-
refreshInterval?: number
38+
refreshInterval?: number | ((latestData: Data | undefined) => number)
3939
refreshWhenHidden?: boolean
4040
refreshWhenOffline?: boolean
4141
revalidateOnFocus: boolean

src/use-swr.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import { defaultConfig } from './utils/config'
33
import { SWRGlobalState, GlobalState } from './utils/global-state'
44
import { IS_SERVER, rAF, useIsomorphicLayoutEffect } from './utils/env'
55
import { serialize } from './utils/serialize'
6-
import { isUndefined, UNDEFINED, OBJECT, mergeObjects } from './utils/helper'
6+
import {
7+
isUndefined,
8+
UNDEFINED,
9+
OBJECT,
10+
mergeObjects,
11+
isFunction
12+
} from './utils/helper'
713
import ConfigProvider from './utils/config-context'
814
import { useStateWithDeps } from './utils/state'
915
import { withArgs } from './utils/resolve-args'
@@ -440,11 +446,17 @@ export const useSWRHandler = <Data = any, Error = any>(
440446
let timer: any
441447

442448
function next() {
449+
// Use the passed interval
450+
// ...or invoke the function with the updated data to get the interval
451+
const interval = isFunction(refreshInterval)
452+
? refreshInterval(data)
453+
: refreshInterval
454+
443455
// We only start next interval if `refreshInterval` is not 0, and:
444456
// - `force` is true, which is the start of polling
445457
// - or `timer` is not 0, which means the effect wasn't canceled
446-
if (refreshInterval && timer !== -1) {
447-
timer = setTimeout(execute, refreshInterval)
458+
if (interval && timer !== -1) {
459+
timer = setTimeout(execute, interval)
448460
}
449461
}
450462

test/use-swr-refresh.test.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,4 +374,64 @@ describe('useSWR - refresh', () => {
374374
expect(fetcherWithToken).toBeCalledTimes(5)
375375
expect(fetcherWithToken).toHaveBeenLastCalledWith(`1-${key}`)
376376
})
377+
378+
it('should allow using function as an interval', async () => {
379+
let count = 0
380+
381+
const key = createKey()
382+
function Page() {
383+
const { data } = useSWR(key, () => count++, {
384+
refreshInterval: () => 200,
385+
dedupingInterval: 100
386+
})
387+
return <div>count: {data}</div>
388+
}
389+
390+
renderWithConfig(<Page />)
391+
392+
// hydration
393+
screen.getByText('count:')
394+
395+
// mount
396+
await screen.findByText('count: 0')
397+
398+
await act(() => advanceTimers(200)) // update
399+
screen.getByText('count: 1')
400+
await act(() => advanceTimers(50)) // no update
401+
screen.getByText('count: 1')
402+
await act(() => advanceTimers(150)) // update
403+
screen.getByText('count: 2')
404+
})
405+
406+
it('should pass updated data to refreshInterval', async () => {
407+
let count = 1
408+
409+
const key = createKey()
410+
function Page() {
411+
const { data } = useSWR(key, () => count++, {
412+
refreshInterval: updatedCount => updatedCount * 1000,
413+
dedupingInterval: 100
414+
})
415+
return <div>count: {data}</div>
416+
}
417+
418+
renderWithConfig(<Page />)
419+
420+
// hydration
421+
screen.getByText('count:')
422+
423+
// mount
424+
await screen.findByText('count: 1')
425+
426+
await act(() => advanceTimers(1000)) // updated after 1s
427+
screen.getByText('count: 2')
428+
await act(() => advanceTimers(1000)) // no update
429+
screen.getByText('count: 2')
430+
await act(() => advanceTimers(1000)) // updated after 2s
431+
screen.getByText('count: 3')
432+
await act(() => advanceTimers(2000)) // no update
433+
screen.getByText('count: 3')
434+
await act(() => advanceTimers(1000)) // updated after 3s
435+
screen.getByText('count: 4')
436+
})
377437
})

0 commit comments

Comments
 (0)