@tanstack/react-query 4.14.1 → 4.14.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/react-query",
3
- "version": "4.14.1",
3
+ "version": "4.14.5",
4
4
  "description": "Hooks for managing, caching and syncing asynchronous and remote data in React",
5
5
  "author": "tannerlinsley",
6
6
  "license": "MIT",
@@ -46,7 +46,7 @@
46
46
  "react-error-boundary": "^3.1.4"
47
47
  },
48
48
  "dependencies": {
49
- "@tanstack/query-core": "4.14.1",
49
+ "@tanstack/query-core": "4.14.5",
50
50
  "use-sync-external-store": "^1.2.0"
51
51
  },
52
52
  "peerDependencies": {
@@ -2,7 +2,6 @@ import { fireEvent, waitFor } from '@testing-library/react'
2
2
  import * as React from 'react'
3
3
 
4
4
  import {
5
- Blink,
6
5
  createQueryClient,
7
6
  queryKey,
8
7
  renderWithClient,
@@ -517,24 +516,28 @@ describe('useInfiniteQuery', () => {
517
516
  data: undefined,
518
517
  isFetching: true,
519
518
  isFetchingNextPage: false,
519
+ isRefetching: false,
520
520
  })
521
521
  // Initial fetch done
522
522
  expect(states[1]).toMatchObject({
523
523
  data: { pages: [10] },
524
524
  isFetching: false,
525
525
  isFetchingNextPage: false,
526
+ isRefetching: false,
526
527
  })
527
528
  // Fetch next page
528
529
  expect(states[2]).toMatchObject({
529
530
  data: { pages: [10] },
530
531
  isFetching: true,
531
532
  isFetchingNextPage: true,
533
+ isRefetching: false,
532
534
  })
533
535
  // Fetch next page done
534
536
  expect(states[3]).toMatchObject({
535
537
  data: { pages: [10, 11] },
536
538
  isFetching: false,
537
539
  isFetchingNextPage: false,
540
+ isRefetching: false,
538
541
  })
539
542
  // Fetch previous page
540
543
  expect(states[4]).toMatchObject({
@@ -542,6 +545,7 @@ describe('useInfiniteQuery', () => {
542
545
  isFetching: true,
543
546
  isFetchingNextPage: false,
544
547
  isFetchingPreviousPage: true,
548
+ isRefetching: false,
545
549
  })
546
550
  // Fetch previous page done
547
551
  expect(states[5]).toMatchObject({
@@ -549,6 +553,7 @@ describe('useInfiniteQuery', () => {
549
553
  isFetching: false,
550
554
  isFetchingNextPage: false,
551
555
  isFetchingPreviousPage: false,
556
+ isRefetching: false,
552
557
  })
553
558
  // Refetch
554
559
  expect(states[6]).toMatchObject({
@@ -556,6 +561,7 @@ describe('useInfiniteQuery', () => {
556
561
  isFetching: true,
557
562
  isFetchingNextPage: false,
558
563
  isFetchingPreviousPage: false,
564
+ isRefetching: true,
559
565
  })
560
566
  // Refetch done
561
567
  expect(states[7]).toMatchObject({
@@ -563,6 +569,7 @@ describe('useInfiniteQuery', () => {
563
569
  isFetching: false,
564
570
  isFetchingNextPage: false,
565
571
  isFetchingPreviousPage: false,
572
+ isRefetching: false,
566
573
  })
567
574
  })
568
575
 
@@ -619,24 +626,28 @@ describe('useInfiniteQuery', () => {
619
626
  data: undefined,
620
627
  isFetching: true,
621
628
  isFetchingNextPage: false,
629
+ isRefetching: false,
622
630
  })
623
631
  // Initial fetch done
624
632
  expect(states[1]).toMatchObject({
625
633
  data: { pages: [10] },
626
634
  isFetching: false,
627
635
  isFetchingNextPage: false,
636
+ isRefetching: false,
628
637
  })
629
638
  // Fetch next page
630
639
  expect(states[2]).toMatchObject({
631
640
  data: { pages: [10] },
632
641
  isFetching: true,
633
642
  isFetchingNextPage: true,
643
+ isRefetching: false,
634
644
  })
635
645
  // Fetch next page done
636
646
  expect(states[3]).toMatchObject({
637
647
  data: { pages: [10, 11] },
638
648
  isFetching: false,
639
649
  isFetchingNextPage: false,
650
+ isRefetching: false,
640
651
  })
641
652
  // Fetch previous page
642
653
  expect(states[4]).toMatchObject({
@@ -644,6 +655,7 @@ describe('useInfiniteQuery', () => {
644
655
  isFetching: true,
645
656
  isFetchingNextPage: false,
646
657
  isFetchingPreviousPage: true,
658
+ isRefetching: false,
647
659
  })
648
660
  // Fetch previous page done
649
661
  expect(states[5]).toMatchObject({
@@ -651,6 +663,7 @@ describe('useInfiniteQuery', () => {
651
663
  isFetching: false,
652
664
  isFetchingNextPage: false,
653
665
  isFetchingPreviousPage: false,
666
+ isRefetching: false,
654
667
  })
655
668
  // Refetch
656
669
  expect(states[6]).toMatchObject({
@@ -658,6 +671,7 @@ describe('useInfiniteQuery', () => {
658
671
  isFetching: true,
659
672
  isFetchingNextPage: false,
660
673
  isFetchingPreviousPage: false,
674
+ isRefetching: true,
661
675
  })
662
676
  // Refetch done
663
677
  expect(states[7]).toMatchObject({
@@ -665,6 +679,7 @@ describe('useInfiniteQuery', () => {
665
679
  isFetching: false,
666
680
  isFetchingNextPage: false,
667
681
  isFetchingPreviousPage: false,
682
+ isRefetching: false,
668
683
  })
669
684
  })
670
685
 
@@ -1725,13 +1740,13 @@ describe('useInfiniteQuery', () => {
1725
1740
  const promise = new Promise<string>((resolve, reject) => {
1726
1741
  cancelFn = jest.fn(() => reject('Cancelled'))
1727
1742
  signal?.addEventListener('abort', cancelFn)
1728
- sleep(20).then(() => resolve('OK'))
1743
+ sleep(1000).then(() => resolve('OK'))
1729
1744
  })
1730
1745
 
1731
1746
  return promise
1732
1747
  }
1733
1748
 
1734
- function Page() {
1749
+ function Inner() {
1735
1750
  const state = useInfiniteQuery(key, queryFn)
1736
1751
  return (
1737
1752
  <div>
@@ -1740,14 +1755,25 @@ describe('useInfiniteQuery', () => {
1740
1755
  )
1741
1756
  }
1742
1757
 
1743
- const rendered = renderWithClient(
1744
- queryClient,
1745
- <Blink duration={5}>
1746
- <Page />
1747
- </Blink>,
1748
- )
1758
+ function Page() {
1759
+ const [isVisible, setIsVisible] = React.useState(true)
1760
+
1761
+ return (
1762
+ <>
1763
+ <button onClick={() => setIsVisible(false)}>hide</button>
1764
+ {isVisible && <Inner />}
1765
+ <div>{isVisible ? 'visible' : 'hidden'}</div>
1766
+ </>
1767
+ )
1768
+ }
1769
+
1770
+ const rendered = renderWithClient(queryClient, <Page />)
1771
+
1772
+ await waitFor(() => rendered.getByText('visible'))
1773
+
1774
+ fireEvent.click(rendered.getByRole('button', { name: 'hide' }))
1749
1775
 
1750
- await waitFor(() => rendered.getByText('off'))
1776
+ await waitFor(() => rendered.getByText('hidden'))
1751
1777
 
1752
1778
  expect(cancelFn).toHaveBeenCalled()
1753
1779
  })
@@ -969,12 +969,15 @@ describe('useQuery', () => {
969
969
  select: (data) => data.name,
970
970
  })
971
971
  states.push(state)
972
- return null
972
+
973
+ return <div>{state.data}</div>
973
974
  }
974
975
 
975
- renderWithClient(queryClient, <Page />)
976
+ const rendered = renderWithClient(queryClient, <Page />)
976
977
 
977
- await sleep(10)
978
+ await waitFor(() => {
979
+ rendered.getByText('test')
980
+ })
978
981
 
979
982
  expect(states.length).toBe(2)
980
983
  expect(states[0]).toMatchObject({ data: undefined })
@@ -992,12 +995,15 @@ describe('useQuery', () => {
992
995
  select: (data) => data.name,
993
996
  })
994
997
  states.push(state)
995
- return null
998
+
999
+ return <div>{state.data}</div>
996
1000
  }
997
1001
 
998
- renderWithClient(queryClient, <Page />)
1002
+ const rendered = renderWithClient(queryClient, <Page />)
999
1003
 
1000
- await sleep(10)
1004
+ await waitFor(() => {
1005
+ rendered.getByText('test')
1006
+ })
1001
1007
 
1002
1008
  expect(states.length).toBe(2)
1003
1009
  expect(states[0]).toMatchObject({ data: undefined })
@@ -1016,24 +1022,32 @@ describe('useQuery', () => {
1016
1022
 
1017
1023
  states.push(state)
1018
1024
 
1019
- const { refetch } = state
1025
+ return (
1026
+ <div>
1027
+ <div>{state?.data}</div>
1028
+ <button onClick={() => state.refetch()}>refetch</button>
1029
+ </div>
1030
+ )
1031
+ }
1020
1032
 
1021
- React.useEffect(() => {
1022
- setActTimeout(() => {
1023
- refetch()
1024
- }, 5)
1025
- }, [refetch])
1033
+ const rendered = renderWithClient(queryClient, <Page />)
1026
1034
 
1027
- return null
1028
- }
1035
+ await waitFor(() => {
1036
+ rendered.getByText('test')
1037
+ })
1029
1038
 
1030
- renderWithClient(queryClient, <Page />)
1039
+ fireEvent.click(rendered.getByRole('button', { name: 'refetch' }))
1031
1040
 
1032
- await sleep(10)
1041
+ await waitFor(() => {
1042
+ rendered.getByText('test')
1043
+ })
1033
1044
 
1034
- expect(states.length).toBe(2)
1035
1045
  expect(states[0]).toMatchObject({ data: undefined })
1036
1046
  expect(states[1]).toMatchObject({ data: 'test' })
1047
+
1048
+ // make sure no additional renders happen
1049
+ await sleep(50)
1050
+ expect(states.length).toBe(2)
1037
1051
  })
1038
1052
 
1039
1053
  it('should throw an error when a selector throws', async () => {
@@ -1596,18 +1610,21 @@ describe('useQuery', () => {
1596
1610
 
1597
1611
  states.push(state)
1598
1612
 
1599
- React.useEffect(() => {
1600
- setActTimeout(() => {
1601
- setCount(1)
1602
- }, 20)
1603
- }, [])
1604
-
1605
- return null
1613
+ return (
1614
+ <div>
1615
+ <div>data: {state.data}</div>
1616
+ <button onClick={() => setCount(1)}>setCount</button>
1617
+ </div>
1618
+ )
1606
1619
  }
1607
1620
 
1608
- renderWithClient(queryClient, <Page />)
1621
+ const rendered = renderWithClient(queryClient, <Page />)
1622
+
1623
+ await waitFor(() => rendered.getByText('data: 0'))
1609
1624
 
1610
- await waitFor(() => expect(states.length).toBe(5))
1625
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1626
+
1627
+ await waitFor(() => rendered.getByText('data: 1'))
1611
1628
 
1612
1629
  // Initial
1613
1630
  expect(states[0]).toMatchObject({
@@ -1630,15 +1647,8 @@ describe('useQuery', () => {
1630
1647
  isSuccess: true,
1631
1648
  isPreviousData: true,
1632
1649
  })
1633
- // Hook state update
1634
- expect(states[3]).toMatchObject({
1635
- data: 0,
1636
- isFetching: true,
1637
- isSuccess: true,
1638
- isPreviousData: true,
1639
- })
1640
1650
  // New data
1641
- expect(states[4]).toMatchObject({
1651
+ expect(states[3]).toMatchObject({
1642
1652
  data: 1,
1643
1653
  isFetching: false,
1644
1654
  isSuccess: true,
@@ -2196,38 +2206,6 @@ describe('useQuery', () => {
2196
2206
  expect(states[2]).toMatchObject({ isStale: true })
2197
2207
  })
2198
2208
 
2199
- it('should notify query cache when a query becomes stale', async () => {
2200
- const key = queryKey()
2201
- const states: UseQueryResult<string>[] = []
2202
- const fn = jest.fn()
2203
-
2204
- const unsubscribe = queryCache.subscribe(fn)
2205
-
2206
- function Page() {
2207
- const state = useQuery(key, () => 'test', {
2208
- staleTime: 10,
2209
- })
2210
- states.push(state)
2211
- return null
2212
- }
2213
-
2214
- renderWithClient(queryClient, <Page />)
2215
-
2216
- await sleep(20)
2217
- unsubscribe()
2218
-
2219
- // 1. Query added -> loading
2220
- // 2. Observer result updated -> loading
2221
- // 3. Observer added
2222
- // 4. Query updated -> success
2223
- // 5. Observer result updated -> success
2224
- // 6. Query updated -> stale
2225
- // 7. Observer options updated
2226
- // 8. Observer result updated -> stale
2227
- // 9. Observer options updated
2228
- expect(fn).toHaveBeenCalledTimes(9)
2229
- })
2230
-
2231
2209
  it('should not re-render when it should only re-render on data changes and the data did not change', async () => {
2232
2210
  const key = queryKey()
2233
2211
  const states: UseQueryResult<string>[] = []
@@ -3815,18 +3793,35 @@ describe('useQuery', () => {
3815
3793
 
3816
3794
  results.push(result)
3817
3795
 
3818
- React.useEffect(() => {
3819
- setActTimeout(() => {
3820
- setShouldFetch(false)
3821
- }, 5)
3822
- }, [])
3823
-
3824
- return null
3796
+ return (
3797
+ <div>
3798
+ <div>{result.data}</div>
3799
+ <div>{shouldFetch ? 'enabled' : 'disabled'}</div>
3800
+ <button
3801
+ onClick={() => {
3802
+ setShouldFetch(false)
3803
+ }}
3804
+ >
3805
+ enable
3806
+ </button>
3807
+ </div>
3808
+ )
3825
3809
  }
3826
3810
 
3827
- renderWithClient(queryClient, <Page />)
3811
+ const rendered = renderWithClient(queryClient, <Page />)
3812
+
3813
+ await waitFor(() => {
3814
+ rendered.getByText('fetched data')
3815
+ rendered.getByText('enabled')
3816
+ })
3817
+
3818
+ fireEvent.click(rendered.getByRole('button', { name: /enable/i }))
3819
+
3820
+ await waitFor(() => {
3821
+ rendered.getByText('fetched data')
3822
+ rendered.getByText('disabled')
3823
+ })
3828
3824
 
3829
- await sleep(50)
3830
3825
  expect(results.length).toBe(3)
3831
3826
  expect(results[0]).toMatchObject({ data: 'initial', isStale: true })
3832
3827
  expect(results[1]).toMatchObject({ data: 'fetched data', isStale: true })