File tree Expand file tree Collapse file tree 3 files changed +47
-1
lines changed
packages/toolkit/src/query Expand file tree Collapse file tree 3 files changed +47
-1
lines changed Original file line number Diff line number Diff line change @@ -51,6 +51,7 @@ import { UNINITIALIZED_VALUE } from './constants'
5151import type { ReactHooksModuleOptions } from './module'
5252import { useStableQueryArgs } from './useSerializedStableValue'
5353import { useShallowStableValue } from './useShallowStableValue'
54+ import { useIsMounted } from './useIsMounted'
5455
5556// Copy-pasted from React-Redux
5657const 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
Original file line number Diff line number Diff line change 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+ }
Original file line number Diff line number Diff 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 ) , {
You can’t perform that action at this time.
0 commit comments