Skip to content

Commit d7362d7

Browse files
shudingnevilm-lt
authored andcommitted
1 parent 9fd7e92 commit d7362d7

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
@@ -29,7 +29,7 @@ const WITH_DEDUPE = { dedupe: true }
2929

3030
export const useSWRHandler = <Data = any, Error = any>(
3131
_key: Key,
32-
fn: Fetcher<Data> | null,
32+
fetcher: Fetcher<Data> | null,
3333
config: typeof defaultConfig & SWRConfiguration<Data, Error>
3434
) => {
3535
const {
@@ -68,6 +68,7 @@ export const useSWRHandler = <Data = any, Error = any>(
6868

6969
// Refs to keep the key and config.
7070
const keyRef = useRef(key)
71+
const fetcherRef = useRef(fetcher)
7172
const configRef = useRef(config)
7273
const getConfig = () => configRef.current
7374

@@ -96,7 +97,7 @@ export const useSWRHandler = <Data = any, Error = any>(
9697

9798
// Resolve the current validating state.
9899
const resolveValidating = () => {
99-
if (!key || !fn) return false
100+
if (!key || !fetcher) return false
100101
if (cache.get(keyValidating)) return true
101102

102103
// If it's not mounted yet and it should revalidate on mount, revalidate.
@@ -117,7 +118,14 @@ export const useSWRHandler = <Data = any, Error = any>(
117118
// `fetcher`, to correctly handle the many edge cases.
118119
const revalidate = useCallback(
119120
async (revalidateOpts?: RevalidatorOptions): Promise<boolean> => {
120-
if (!key || !fn || unmountedRef.current || getConfig().isPaused()) {
121+
const currentFetcher = fetcherRef.current
122+
123+
if (
124+
!key ||
125+
!currentFetcher ||
126+
unmountedRef.current ||
127+
getConfig().isPaused()
128+
) {
121129
return false
122130
}
123131

@@ -182,7 +190,7 @@ export const useSWRHandler = <Data = any, Error = any>(
182190

183191
// Start the request and keep the timestamp.
184192
CONCURRENT_PROMISES_TS[key] = getTimestamp()
185-
CONCURRENT_PROMISES[key] = fn(...fnArgs)
193+
CONCURRENT_PROMISES[key] = currentFetcher(...fnArgs)
186194
}
187195

188196
// Wait until the ongoing request is done. Deduplication is also
@@ -319,8 +327,9 @@ export const useSWRHandler = <Data = any, Error = any>(
319327
[]
320328
)
321329

322-
// Always update config.
330+
// Always update fetcher and config refs.
323331
useIsomorphicLayoutEffect(() => {
332+
fetcherRef.current = fetcher
324333
configRef.current = config
325334
})
326335

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)