Skip to content

Commit c7a18eb

Browse files
authored
fix(react-query-persist-client): don't double-restore in StrictMode (#6020)
1 parent 3d64084 commit c7a18eb

File tree

2 files changed

+85
-14
lines changed

2 files changed

+85
-14
lines changed

packages/react-query-persist-client/src/PersistQueryClientProvider.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,31 @@ export const PersistQueryClientProvider = ({
2020
}: PersistQueryClientProviderProps): JSX.Element => {
2121
const [isRestoring, setIsRestoring] = React.useState(true)
2222
const refs = React.useRef({ persistOptions, onSuccess })
23+
const didRestore = React.useRef(false)
2324

2425
React.useEffect(() => {
2526
refs.current = { persistOptions, onSuccess }
2627
})
2728

2829
React.useEffect(() => {
29-
let isStale = false
30-
setIsRestoring(true)
31-
const [unsubscribe, promise] = persistQueryClient({
32-
...refs.current.persistOptions,
33-
queryClient: client,
34-
})
35-
36-
promise.then(() => {
37-
if (!isStale) {
30+
if (!didRestore.current) {
31+
didRestore.current = true
32+
setIsRestoring(true)
33+
const [unsubscribe, promise] = persistQueryClient({
34+
...refs.current.persistOptions,
35+
queryClient: client,
36+
})
37+
38+
promise.then(() => {
3839
refs.current.onSuccess?.()
3940
setIsRestoring(false)
40-
}
41-
})
41+
})
4242

43-
return () => {
44-
isStale = true
45-
unsubscribe()
43+
return () => {
44+
unsubscribe()
45+
}
4646
}
47+
return undefined
4748
}, [client])
4849

4950
return (

packages/react-query-persist-client/src/__tests__/PersistQueryClientProvider.test.tsx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,4 +538,74 @@ describe('PersistQueryClientProvider', () => {
538538
data: 'queryFn2',
539539
})
540540
})
541+
542+
test('should only restore once in StrictMode', async () => {
543+
let restoreCount = 0
544+
const createPersister = (): Persister => {
545+
let storedState: PersistedClient | undefined
546+
547+
return {
548+
async persistClient(persistClient) {
549+
storedState = persistClient
550+
},
551+
async restoreClient() {
552+
restoreCount++
553+
await sleep(10)
554+
return storedState
555+
},
556+
removeClient() {
557+
storedState = undefined
558+
},
559+
}
560+
}
561+
562+
const key = queryKey()
563+
564+
const queryClient = createQueryClient()
565+
await queryClient.prefetchQuery(key, () => Promise.resolve('hydrated'))
566+
567+
const persister = createPersister()
568+
569+
const onSuccess = jest.fn()
570+
571+
await persistQueryClientSave({ queryClient, persister })
572+
573+
queryClient.clear()
574+
575+
function Page() {
576+
const state = useQuery({
577+
queryKey: key,
578+
queryFn: async () => {
579+
await sleep(10)
580+
return 'fetched'
581+
},
582+
})
583+
584+
return (
585+
<div>
586+
<h1>{state.data}</h1>
587+
<h2>fetchStatus: {state.fetchStatus}</h2>
588+
</div>
589+
)
590+
}
591+
592+
const rendered = render(
593+
<React.StrictMode>
594+
<PersistQueryClientProvider
595+
client={queryClient}
596+
persistOptions={{ persister }}
597+
onSuccess={onSuccess}
598+
>
599+
<Page />
600+
</PersistQueryClientProvider>
601+
</React.StrictMode>,
602+
)
603+
604+
await waitFor(() => rendered.getByText('fetchStatus: idle'))
605+
await waitFor(() => rendered.getByText('hydrated'))
606+
await waitFor(() => rendered.getByText('fetched'))
607+
608+
expect(onSuccess).toHaveBeenCalledTimes(1)
609+
expect(restoreCount).toBe(1)
610+
})
541611
})

0 commit comments

Comments
 (0)