@@ -3528,6 +3528,124 @@ describe('createQuery', () => {
35283528 ] )
35293529 } )
35303530
3531+ // See https://github.com/TanStack/query/issues/7711
3532+ it ( 'race condition: should cleanup observers after component that created the query is unmounted #1' , async ( ) => {
3533+ const key = queryKey ( )
3534+
3535+ function Component ( ) {
3536+ let val = 1
3537+ const dataQuery = createQuery ( ( ) => ( {
3538+ queryKey : [ key ] ,
3539+ queryFn : ( ) => {
3540+ return val ++
3541+ } ,
3542+ } ) )
3543+
3544+ return (
3545+ < div >
3546+ < p > component</ p >
3547+ < p > data: { String ( dataQuery . data ) } </ p >
3548+ </ div >
3549+ )
3550+ }
3551+
3552+ const Outer = ( ) => {
3553+ const [ showComp , setShowComp ] = createSignal ( true )
3554+ return (
3555+ < div >
3556+ < button
3557+ onClick = { ( ) => {
3558+ queryClient . invalidateQueries ( )
3559+ setShowComp ( ! showComp ( ) )
3560+ } }
3561+ >
3562+ toggle
3563+ </ button >
3564+ { showComp ( ) ? < Component /> : < div > not showing</ div > }
3565+ </ div >
3566+ )
3567+ }
3568+
3569+ const rendered = render ( ( ) => (
3570+ < QueryClientProvider client = { queryClient } >
3571+ < Outer />
3572+ </ QueryClientProvider >
3573+ ) )
3574+
3575+ await waitFor ( ( ) => rendered . getByText ( 'component' ) )
3576+ fireEvent . click ( rendered . getByText ( 'toggle' ) )
3577+ await waitFor ( ( ) => rendered . getByText ( 'not showing' ) )
3578+ fireEvent . click ( rendered . getByText ( 'toggle' ) )
3579+ await waitFor ( ( ) => rendered . getByText ( 'component' ) )
3580+ fireEvent . click ( rendered . getByText ( 'toggle' ) )
3581+ await waitFor ( ( ) => rendered . getByText ( 'not showing' ) )
3582+
3583+ const entry = queryClient . getQueryCache ( ) . find ( {
3584+ queryKey : [ key ] ,
3585+ } ) !
3586+
3587+ expect ( entry . getObserversCount ( ) ) . toBe ( 0 )
3588+ } )
3589+
3590+ // See https://github.com/TanStack/query/issues/7711
3591+ it ( 'race condition: should cleanup observers after component that created the query is unmounted #2' , async ( ) => {
3592+ const key = queryKey ( )
3593+
3594+ function Component ( ) {
3595+ let val = 1
3596+ const dataQuery = createQuery ( ( ) => ( {
3597+ queryKey : [ key ] ,
3598+ queryFn : ( ) => {
3599+ return val ++
3600+ } ,
3601+ } ) )
3602+
3603+ return (
3604+ < div >
3605+ < p > component</ p >
3606+ < p > data: { String ( dataQuery . data ) } </ p >
3607+ </ div >
3608+ )
3609+ }
3610+
3611+ const Outer = ( ) => {
3612+ const [ showComp , setShowComp ] = createSignal ( true )
3613+ return (
3614+ < div >
3615+ < button
3616+ onClick = { ( ) => {
3617+ queueMicrotask ( ( ) => setShowComp ( ! showComp ( ) ) )
3618+ queryClient . invalidateQueries ( )
3619+ } }
3620+ >
3621+ toggle
3622+ </ button >
3623+ { showComp ( ) ? < Component /> : < div > not showing</ div > }
3624+ </ div >
3625+ )
3626+ }
3627+
3628+ const rendered = render ( ( ) => (
3629+ < QueryClientProvider client = { queryClient } >
3630+ < Outer />
3631+ </ QueryClientProvider >
3632+ ) )
3633+
3634+ await waitFor ( ( ) => rendered . getByText ( 'component' ) )
3635+ fireEvent . click ( rendered . getByText ( 'toggle' ) )
3636+ await waitFor ( ( ) => rendered . getByText ( 'not showing' ) )
3637+ fireEvent . click ( rendered . getByText ( 'toggle' ) )
3638+ await waitFor ( ( ) => rendered . getByText ( 'component' ) )
3639+ fireEvent . click ( rendered . getByText ( 'toggle' ) )
3640+ await waitFor ( ( ) => rendered . getByText ( 'not showing' ) )
3641+
3642+ const entry = queryClient . getQueryCache ( ) . find ( {
3643+ queryKey : [ key ] ,
3644+ } ) !
3645+
3646+ expect ( entry . getObserversCount ( ) ) . toBe ( 0 )
3647+ } )
3648+
35313649 it ( 'should mark query as fetching, when using initialData' , async ( ) => {
35323650 const key = queryKey ( )
35333651 const results : Array < DefinedCreateQueryResult < string > > = [ ]
0 commit comments