Skip to content

Commit 9dd574e

Browse files
authored
fix #1680 (#1720)
1 parent 0e3b7d5 commit 9dd574e

File tree

4 files changed

+56
-16
lines changed

4 files changed

+56
-16
lines changed

src/utils/cache.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ export const initCache = <Data = any>(
4141
// If there's no global state bound to the provider, create a new one with the
4242
// new mutate function.
4343
const EVENT_REVALIDATORS = {}
44-
const mutate = internalMutate.bind(UNDEFINED, provider) as ScopedMutator<
45-
Data
46-
>
44+
const mutate = internalMutate.bind(
45+
UNDEFINED,
46+
provider
47+
) as ScopedMutator<Data>
4748
let unmount = noop
4849

4950
// Update the state if it's new, or the provider has been extended.
@@ -60,18 +61,30 @@ export const initCache = <Data = any>(
6061
// This is a new provider, we need to initialize it and setup DOM events
6162
// listeners for `focus` and `reconnect` actions.
6263
if (!IS_SERVER) {
64+
// When listening to the native events for auto revalidations,
65+
// we intentionally put a delay (setTimeout) here to make sure they are
66+
// fired after immediate JavaScript executions, which can possibly be
67+
// React's state updates.
68+
// This avoids some unnecessary revalidations such as
69+
// https://github.com/vercel/swr/issues/1680.
6370
const releaseFocus = opts.initFocus(
64-
revalidateAllKeys.bind(
71+
setTimeout.bind(
6572
UNDEFINED,
66-
EVENT_REVALIDATORS,
67-
revalidateEvents.FOCUS_EVENT
73+
revalidateAllKeys.bind(
74+
UNDEFINED,
75+
EVENT_REVALIDATORS,
76+
revalidateEvents.FOCUS_EVENT
77+
)
6878
)
6979
)
7080
const releaseReconnect = opts.initReconnect(
71-
revalidateAllKeys.bind(
81+
setTimeout.bind(
7282
UNDEFINED,
73-
EVENT_REVALIDATORS,
74-
revalidateEvents.RECONNECT_EVENT
83+
revalidateAllKeys.bind(
84+
UNDEFINED,
85+
EVENT_REVALIDATORS,
86+
revalidateEvents.RECONNECT_EVENT
87+
)
7588
)
7689
)
7790
unmount = () => {

src/utils/web-preset.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,21 @@ const isVisible = () => {
3636
return true
3737
}
3838

39-
const initFocus = (cb: () => void) => {
39+
const initFocus = (callback: () => void) => {
4040
// focus revalidate
41-
onDocumentEvent('visibilitychange', cb)
42-
onWindowEvent('focus', cb)
41+
onDocumentEvent('visibilitychange', callback)
42+
onWindowEvent('focus', callback)
4343
return () => {
44-
offDocumentEvent('visibilitychange', cb)
45-
offWindowEvent('focus', cb)
44+
offDocumentEvent('visibilitychange', callback)
45+
offWindowEvent('focus', callback)
4646
}
4747
}
4848

49-
const initReconnect = (cb: () => void) => {
49+
const initReconnect = (callback: () => void) => {
5050
// revalidate on reconnected
5151
const onOnline = () => {
5252
online = true
53-
cb()
53+
callback()
5454
}
5555
// nothing to revalidate, just update the status
5656
const onOffline = () => {

test/use-swr-cache.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ describe('useSWR - cache provider', () => {
183183
await screen.findByText('0')
184184
await nextTick()
185185
await focusOn(window)
186+
await nextTick()
186187
screen.getByText('1')
187188
})
188189

@@ -396,6 +397,7 @@ describe('useSWR - global cache', () => {
396397
await screen.findByText('0')
397398
await nextTick()
398399
await focusOn(window)
400+
await nextTick()
399401
screen.getByText('1')
400402
})
401403

test/use-swr-focus.test.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,4 +220,29 @@ describe('useSWR - focus', () => {
220220
await focusWindow()
221221
await screen.findByText('data: 1')
222222
})
223+
224+
it('should not revalidate on focus when key changes in the same tick', async () => {
225+
const fetchLogs = []
226+
227+
function Page() {
228+
const [key, setKey] = useState(() => createKey())
229+
useSWR(key, k => fetchLogs.push(k), {
230+
revalidateOnFocus: true,
231+
dedupingInterval: 0
232+
})
233+
return <div onClick={() => setKey(createKey())}>change key</div>
234+
}
235+
236+
renderWithConfig(<Page />)
237+
await waitForNextTick()
238+
239+
fireEvent.focus(window)
240+
fireEvent.click(screen.getByText('change key'))
241+
242+
await waitForNextTick()
243+
244+
// Only fetched twice with the initial and the new keys.
245+
expect(fetchLogs.length).toBe(2)
246+
expect(fetchLogs[0]).not.toEqual(fetchLogs[1])
247+
})
223248
})

0 commit comments

Comments
 (0)