File tree Expand file tree Collapse file tree
react-query/src/__tests__ Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -118,29 +118,30 @@ export class QueriesObserver<
118118observer . getCurrentResult ( ) ,
119119)
120120
121+ const hasLengthChange = prevObservers . length !== newObservers . length
121122const hasIndexChange = newObservers . some (
122123( observer , index ) => observer !== prevObservers [ index ] ,
123124)
125+ const hasStructuralChange = hasLengthChange || hasIndexChange
124126
125- const hasResultChange =
126- prevObservers . length === newObservers . length && ! hasIndexChange
127- ? newResult . some ( ( result , index ) => {
128- const prev = this . #result[ index ]
129- return ! prev || ! shallowEqualObjects ( result , prev )
130- } )
131- : true
127+ const hasResultChange = hasStructuralChange
128+ ? true
129+ : newResult . some ( ( result , index ) => {
130+ const prev = this . #result[ index ]
131+ return ! prev || ! shallowEqualObjects ( result , prev )
132+ } )
132133
133- if ( ! hasIndexChange && ! hasResultChange ) return
134+ if ( ! hasStructuralChange && ! hasResultChange ) return
134135
135- if ( hasIndexChange ) {
136+ if ( hasStructuralChange ) {
136137this . #observers = newObservers
137138}
138139
139140this . #result = newResult
140141
141142if ( ! this . hasListeners ( ) ) return
142143
143- if ( hasIndexChange ) {
144+ if ( hasStructuralChange ) {
144145difference ( prevObservers , newObservers ) . forEach ( ( observer ) => {
145146observer . destroy ( )
146147} )
Original file line number Diff line number Diff line change @@ -1741,4 +1741,74 @@ describe('useQueries', () => {
17411741// still no extra calls to combine
17421742expect ( spy ) . toHaveBeenCalledTimes ( 3 )
17431743} )
1744+
1745+ it ( 'should not cause infinite re-renders when removing last query' , async ( ) => {
1746+ let renderCount = 0
1747+
1748+ function Page ( ) {
1749+ const [ queries , setQueries ] = React . useState ( [
1750+ {
1751+ queryKey : [ 'query1' ] ,
1752+ queryFn : ( ) => 'data1' ,
1753+ } ,
1754+ {
1755+ queryKey : [ 'query2' ] ,
1756+ queryFn : ( ) => 'data2' ,
1757+ } ,
1758+ ] )
1759+ renderCount ++
1760+
1761+ const result = useQueries ( { queries } )
1762+
1763+ return (
1764+ < div >
1765+ < div data-testid = "render-count" > renders: { renderCount } </ div >
1766+ < div data-testid = "query-count" > queries: { result . length } </ div >
1767+ < button
1768+ onClick = { ( ) => {
1769+ setQueries ( [
1770+ {
1771+ queryKey : [ 'query1' ] ,
1772+ queryFn : ( ) => 'data1' ,
1773+ } ,
1774+ ] )
1775+ } }
1776+ >
1777+ remove last
1778+ </ button >
1779+ < button
1780+ onClick = { ( ) => {
1781+ setQueries ( [
1782+ {
1783+ queryKey : [ 'query2' ] ,
1784+ queryFn : ( ) => 'data2' ,
1785+ } ,
1786+ ] )
1787+ } }
1788+ >
1789+ remove first
1790+ </ button >
1791+ </ div >
1792+ )
1793+ }
1794+
1795+ const rendered = renderWithClient ( queryClient , < Page /> )
1796+
1797+ await vi . advanceTimersByTimeAsync ( 0 )
1798+ renderCount = 0
1799+
1800+ fireEvent . click ( rendered . getByRole ( 'button' , { name : / r e m o v e l a s t / i} ) )
1801+ await vi . advanceTimersByTimeAsync ( 100 )
1802+
1803+ expect ( renderCount ) . toBeLessThan ( 10 )
1804+ expect ( rendered . getByTestId ( 'query-count' ) . textContent ) . toBe ( 'queries: 1' )
1805+
1806+ renderCount = 0
1807+
1808+ fireEvent . click ( rendered . getByRole ( 'button' , { name : / r e m o v e f i r s t / i} ) )
1809+ await vi . advanceTimersByTimeAsync ( 100 )
1810+
1811+ expect ( renderCount ) . toBeLessThan ( 10 )
1812+ expect ( rendered . getByTestId ( 'query-count' ) . textContent ) . toBe ( 'queries: 1' )
1813+ } )
17441814} )
You can’t perform that action at this time.
0 commit comments