@@ -3528,6 +3528,124 @@ describe('createQuery', () => {
3528
3528
] )
3529
3529
} )
3530
3530
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
+
3531
3649
it ( 'should mark query as fetching, when using initialData' , async ( ) => {
3532
3650
const key = queryKey ( )
3533
3651
const results : Array < DefinedCreateQueryResult < string > > = [ ]
0 commit comments