Skip to content

Commit d7dd7f3

Browse files
committed
resolves #1131
1 parent e167752 commit d7dd7f3

File tree

2 files changed

+50
-5
lines changed

2 files changed

+50
-5
lines changed

src/use-swr.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const WITH_DEDUPE = { dedupe: true }
3535

3636
export const useSWRHandler = <Data = any, Error = any>(
3737
_key: Key,
38-
fn: Fetcher<Data> | null,
38+
fetcher: Fetcher<Data> | null,
3939
config: typeof defaultConfig & SWRConfiguration<Data, Error>
4040
) => {
4141
const {
@@ -74,6 +74,7 @@ export const useSWRHandler = <Data = any, Error = any>(
7474

7575
// Refs to keep the key and config.
7676
const keyRef = useRef(key)
77+
const fetcherRef = useRef(fetcher)
7778
const configRef = useRef(config)
7879
const getConfig = () => configRef.current
7980

@@ -106,7 +107,7 @@ export const useSWRHandler = <Data = any, Error = any>(
106107

107108
// Resolve the current validating state.
108109
const resolveValidating = () => {
109-
if (!key || !fn) return false
110+
if (!key || !fetcher) return false
110111
if (cache.get(keyValidating)) return true
111112

112113
// If it's not mounted yet and it should revalidate on mount, revalidate.
@@ -127,7 +128,14 @@ export const useSWRHandler = <Data = any, Error = any>(
127128
// `fetcher`, to correctly handle the many edge cases.
128129
const revalidate = useCallback(
129130
async (revalidateOpts?: RevalidatorOptions): Promise<boolean> => {
130-
if (!key || !fn || unmountedRef.current || getConfig().isPaused()) {
131+
const currentFetcher = fetcherRef.current
132+
133+
if (
134+
!key ||
135+
!currentFetcher ||
136+
unmountedRef.current ||
137+
getConfig().isPaused()
138+
) {
131139
return false
132140
}
133141

@@ -196,7 +204,7 @@ export const useSWRHandler = <Data = any, Error = any>(
196204

197205
// Start the request and keep the timestamp.
198206
CONCURRENT_PROMISES_TS[key] = getTimestamp()
199-
CONCURRENT_PROMISES[key] = fn(...fnArgs)
207+
CONCURRENT_PROMISES[key] = currentFetcher(...fnArgs)
200208
}
201209

202210
// Wait until the ongoing request is done. Deduplication is also
@@ -345,8 +353,9 @@ export const useSWRHandler = <Data = any, Error = any>(
345353
[]
346354
)
347355

348-
// Always update config.
356+
// Always update fetcher and config refs.
349357
useIsomorphicLayoutEffect(() => {
358+
fetcherRef.current = fetcher
350359
configRef.current = config
351360
})
352361

test/use-swr-fetcher.test.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { act, screen } from '@testing-library/react'
2+
import React, { useState } from 'react'
3+
import useSWR from 'swr'
4+
import { createKey, renderWithConfig, nextTick } from './utils'
5+
6+
describe('useSWR - fetcher', () => {
7+
// https://github.com/vercel/swr/issues/1131
8+
it('should use the latest fetcher reference', async () => {
9+
const key = createKey()
10+
let fetcher = () => 'foo'
11+
let mutate
12+
let rerender
13+
14+
function Page() {
15+
const { data, mutate: boundMutate } = useSWR(key, fetcher)
16+
rerender = useState({})[1]
17+
mutate = boundMutate
18+
19+
return <div>data:{data}</div>
20+
}
21+
22+
renderWithConfig(<Page />)
23+
await nextTick()
24+
screen.getByText('data:foo')
25+
26+
// Change the fetcher and make sure the ref is updated.
27+
fetcher = () => 'bar'
28+
act(() => rerender({}))
29+
30+
// Revalidate.
31+
await act(() => mutate())
32+
33+
// Should fetch with the new fetcher.
34+
await screen.findByText('data:bar')
35+
})
36+
})

0 commit comments

Comments
 (0)