Skip to content

Commit ddec408

Browse files
committed
Make refetch after unmount a no-op
1 parent ee22bef commit ddec408

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

packages/toolkit/src/query/react/buildHooks.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { UNINITIALIZED_VALUE } from './constants'
5151
import type { ReactHooksModuleOptions } from './module'
5252
import { useStableQueryArgs } from './useSerializedStableValue'
5353
import { useShallowStableValue } from './useShallowStableValue'
54+
import { useIsMounted } from './useIsMounted'
5455

5556
// Copy-pasted from React-Redux
5657
const canUseDOM = () =>
@@ -1118,20 +1119,27 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
11181119
}
11191120
}, [])
11201121

1122+
const getIsMounted = useIsMounted()
1123+
11211124
return useMemo(
11221125
() => ({
11231126
/**
11241127
* A method to manually refetch data for the query
11251128
*/
11261129
refetch: () => {
1130+
// If `refetch` gets called after the component is unmounted,
1131+
// this should be a no-op
1132+
if (!getIsMounted()) {
1133+
return
1134+
}
11271135
if (!promiseRef.current)
11281136
throw new Error(
11291137
'Cannot refetch a query that has not been started yet.',
11301138
)
11311139
return promiseRef.current?.refetch()
11321140
},
11331141
}),
1134-
[],
1142+
[getIsMounted],
11351143
)
11361144
}
11371145

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { useCallback, useLayoutEffect, useRef } from 'react'
2+
3+
export function useIsMounted(): () => boolean {
4+
const mountedRef = useRef(false)
5+
const get = useCallback(() => mountedRef.current, [])
6+
7+
useLayoutEffect(() => {
8+
mountedRef.current = true
9+
10+
return () => {
11+
mountedRef.current = false
12+
}
13+
}, [])
14+
15+
return get
16+
}

packages/toolkit/src/query/tests/buildHooks.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,28 @@ describe('hooks tests', () => {
812812
await screen.findByText('ID: 3')
813813
})
814814

815+
test('refetch does not throw an error if run after unmount', async () => {
816+
let refetchFunction: () => {}
817+
818+
function User() {
819+
const { refetch } = api.endpoints.getUser.useQuery(1)
820+
821+
refetchFunction = refetch
822+
823+
return (
824+
<div>
825+
<button>Refetch</button>
826+
</div>
827+
)
828+
}
829+
830+
const { unmount } = render(<User />, { wrapper: storeRef.wrapper })
831+
832+
unmount()
833+
834+
expect(() => refetchFunction()).not.toThrow()
835+
})
836+
815837
test(`useQuery shouldn't call args serialization if request skipped`, async () => {
816838
expect(() =>
817839
renderHook(() => api.endpoints.queryWithDeepArg.useQuery(skipToken), {

0 commit comments

Comments
 (0)