Skip to content

Commit aee9d46

Browse files
committed
fix: avoid creating new snapshot if cache was not updated at client during streaming
close vercel#2473 x-ref vercel#2391
1 parent ede4c54 commit aee9d46

File tree

5 files changed

+26
-36
lines changed

5 files changed

+26
-36
lines changed

core/use-swr.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,17 @@ export const useSWRHandler = <Data = any, Error = any>(
160160
...snapshot
161161
}
162162
}
163-
163+
const cachedData = getCache()
164+
const initialData = getInitialCache()
165+
const clientSnapshot = getSelectedCache(cachedData)
166+
const serverSnapshot =
167+
cachedData === initialData
168+
? clientSnapshot
169+
: getSelectedCache(initialData)
164170
// To make sure that we are returning the same object reference to avoid
165171
// unnecessary re-renders, we keep the previous snapshot and use deep
166172
// comparison to check if we need to return a new one.
167-
let memorizedSnapshot = getSelectedCache(getCache())
168-
const memorizedInitialSnapshot = getSelectedCache(getInitialCache())
173+
let memorizedSnapshot = clientSnapshot
169174

170175
return [
171176
() => {
@@ -174,7 +179,7 @@ export const useSWRHandler = <Data = any, Error = any>(
174179
? memorizedSnapshot
175180
: (memorizedSnapshot = newSnapshot)
176181
},
177-
() => memorizedInitialSnapshot
182+
() => serverSnapshot
178183
]
179184
// eslint-disable-next-line react-hooks/exhaustive-deps
180185
}, [cache, key])

e2e/site/pages/initial-render.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import useSWR from 'swr'
2+
import { Profiler } from 'react'
23

34
const useFetchUser = () =>
45
useSWR(
@@ -11,8 +12,20 @@ const useFetchUser = () =>
1112
})
1213
)
1314

14-
export default function UserSWR() {
15+
function UserSWR() {
1516
useFetchUser()
16-
console.log('UserSWR rendered')
1717
return <div>SWRTest</div>
1818
}
19+
20+
export default function SWRTest() {
21+
return (
22+
<Profiler
23+
id="swr"
24+
onRender={() => {
25+
;(window as any).onRender('UserSWR rendered')
26+
}}
27+
>
28+
<UserSWR />
29+
</Profiler>
30+
)
31+
}

e2e/test/initial-render.test.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,7 @@ test.describe('rendering', () => {
55
page
66
}) => {
77
const log: any[] = []
8-
await page.exposeFunction('consoleLog', (msg: any) => log.push(msg))
9-
await page.addInitScript(`
10-
const log = window.console.log
11-
window.console.log = (...args) => {
12-
consoleLog(...args)
13-
log(...args)
14-
}
15-
`)
8+
await page.exposeFunction('onRender', (msg: any) => log.push(msg))
169
await page.goto('./initial-render', { waitUntil: 'commit' })
1710
await expect(page.getByText('SWRTest')).toBeVisible()
1811
expect(log).toHaveLength(1)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
"clean": "pnpm -r run clean && rimraf playwright-report test-result",
7878
"watch": "pnpm -r run watch",
7979
"build": "pnpm build-package _internal && pnpm build-package core && pnpm build-package infinite && pnpm build-package immutable && pnpm build-package mutation && pnpm build-package subscription",
80-
"build:e2e": "pnpm next build e2e/site",
80+
"build:e2e": "pnpm next build e2e/site -- --profile",
8181
"build-package": "bunchee index.ts --cwd",
8282
"types:check": "pnpm -r run types:check",
8383
"prepublishOnly": "pnpm clean && pnpm build",

test/use-swr-integration.test.tsx

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -592,25 +592,4 @@ describe('useSWR', () => {
592592
]
593593
`)
594594
})
595-
596-
it.skip('should not render if the result of swr is not used', async () => {
597-
const key = createKey()
598-
const fetcher = jest.fn(() => createResponse(key, { delay: 100 }))
599-
const onRender = jest.fn()
600-
function Page() {
601-
useSWR(key, fetcher)
602-
return <div>test</div>
603-
}
604-
function App() {
605-
return (
606-
<Profiler id={key} onRender={onRender}>
607-
<Page />
608-
</Profiler>
609-
)
610-
}
611-
renderWithConfig(<App />)
612-
await sleep(200)
613-
expect(fetcher).toBeCalledTimes(1)
614-
expect(onRender).toBeCalledTimes(1)
615-
})
616595
})

0 commit comments

Comments
 (0)