@tanstack/react-query 4.13.5 → 4.14.1

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.13.5",
3
+ "version": "4.14.1",
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.13.4",
49
+ "@tanstack/query-core": "4.14.1",
50
50
  "use-sync-external-store": "^1.2.0"
51
51
  },
52
52
  "peerDependencies": {
@@ -80,6 +80,14 @@ export const QueryClientProvider = ({
80
80
  }
81
81
  }, [client])
82
82
 
83
+ if (process.env.NODE_ENV !== 'production' && contextSharing) {
84
+ client
85
+ .getLogger()
86
+ .error(
87
+ `The contextSharing option has been deprecated and will be removed in the next major version`,
88
+ )
89
+ }
90
+
83
91
  const Context = getQueryClientContext(context, contextSharing)
84
92
 
85
93
  return (
@@ -12,7 +12,7 @@ import {
12
12
  dehydrate,
13
13
  hydrate,
14
14
  } from '..'
15
- import { createQueryClient, mockLogger, setIsServer, sleep } from './utils'
15
+ import { createQueryClient, setIsServer, sleep } from './utils'
16
16
 
17
17
  const isReact18 = () => (process.env.REACTJS_VERSION || '18') === '18'
18
18
 
@@ -55,6 +55,9 @@ describe('Server side rendering with de/rehydration', () => {
55
55
  globalThis.IS_REACT_ACT_ENVIRONMENT = previousIsReactActEnvironment
56
56
  })
57
57
  it('should not mismatch on success', async () => {
58
+ const consoleMock = jest.spyOn(console, 'error')
59
+ consoleMock.mockImplementation(() => undefined)
60
+
58
61
  if (!isReact18()) {
59
62
  return
60
63
  }
@@ -118,15 +121,23 @@ describe('Server side rendering with de/rehydration', () => {
118
121
  )
119
122
 
120
123
  // Check that we have no React hydration mismatches
121
- expect(mockLogger.error).not.toHaveBeenCalled()
124
+ // this should be zero calls and can be changed once we drop react17 support
125
+ expect(consoleMock).toHaveBeenNthCalledWith(
126
+ 1,
127
+ 'Warning: You are importing hydrateRoot from "react-dom" which is not supported. You should instead import it from "react-dom/client".',
128
+ )
122
129
  expect(fetchDataSuccess).toHaveBeenCalledTimes(2)
123
130
  expect(el.innerHTML).toBe(expectedMarkup)
124
131
 
125
132
  unmount()
126
133
  queryClient.clear()
134
+ consoleMock.mockRestore()
127
135
  })
128
136
 
129
137
  it('should not mismatch on error', async () => {
138
+ const consoleMock = jest.spyOn(console, 'error')
139
+ consoleMock.mockImplementation(() => undefined)
140
+
130
141
  if (!isReact18()) {
131
142
  return
132
143
  }
@@ -187,7 +198,7 @@ describe('Server side rendering with de/rehydration', () => {
187
198
  )
188
199
 
189
200
  // We expect exactly one console.error here, which is from the
190
- expect(mockLogger.error).toHaveBeenCalledTimes(1)
201
+ expect(consoleMock).toHaveBeenCalledTimes(1)
191
202
  expect(fetchDataError).toHaveBeenCalledTimes(2)
192
203
  expect(el.innerHTML).toBe(expectedMarkup)
193
204
  await sleep(50)
@@ -198,9 +209,13 @@ describe('Server side rendering with de/rehydration', () => {
198
209
 
199
210
  unmount()
200
211
  queryClient.clear()
212
+ consoleMock.mockRestore()
201
213
  })
202
214
 
203
215
  it('should not mismatch on queries that were not prefetched', async () => {
216
+ const consoleMock = jest.spyOn(console, 'error')
217
+ consoleMock.mockImplementation(() => undefined)
218
+
204
219
  if (!isReact18()) {
205
220
  return
206
221
  }
@@ -254,7 +269,11 @@ describe('Server side rendering with de/rehydration', () => {
254
269
  )
255
270
 
256
271
  // Check that we have no React hydration mismatches
257
- expect(mockLogger.error).not.toHaveBeenCalled()
272
+ // this should be zero calls and can be changed once we drop react17 support
273
+ expect(consoleMock).toHaveBeenNthCalledWith(
274
+ 1,
275
+ 'Warning: You are importing hydrateRoot from "react-dom" which is not supported. You should instead import it from "react-dom/client".',
276
+ )
258
277
  expect(fetchDataSuccess).toHaveBeenCalledTimes(1)
259
278
  expect(el.innerHTML).toBe(expectedMarkup)
260
279
  await sleep(50)
@@ -265,5 +284,6 @@ describe('Server side rendering with de/rehydration', () => {
265
284
 
266
285
  unmount()
267
286
  queryClient.clear()
287
+ consoleMock.mockRestore()
268
288
  })
269
289
  })
@@ -1769,18 +1769,30 @@ describe('useQuery', () => {
1769
1769
 
1770
1770
  states.push(state)
1771
1771
 
1772
- React.useEffect(() => {
1773
- setActTimeout(() => {
1774
- setCount(1)
1775
- }, 20)
1776
- }, [])
1777
-
1778
- return null
1772
+ return (
1773
+ <div>
1774
+ <h1>
1775
+ data: {state.data}, count: {count}, isFetching:{' '}
1776
+ {String(state.isFetching)}
1777
+ </h1>
1778
+ <button onClick={() => setCount(1)}>inc</button>
1779
+ </div>
1780
+ )
1779
1781
  }
1780
1782
 
1781
- renderWithClient(queryClient, <Page />)
1783
+ const rendered = renderWithClient(queryClient, <Page />)
1782
1784
 
1783
- await waitFor(() => expect(states.length).toBe(5))
1785
+ await waitFor(() =>
1786
+ rendered.getByText('data: 0, count: 0, isFetching: false'),
1787
+ )
1788
+
1789
+ fireEvent.click(rendered.getByRole('button', { name: 'inc' }))
1790
+
1791
+ await waitFor(() =>
1792
+ rendered.getByText('data: 1, count: 1, isFetching: false'),
1793
+ )
1794
+
1795
+ expect(states.length).toBe(5)
1784
1796
 
1785
1797
  // Initial
1786
1798
  expect(states[0]).toMatchObject({
@@ -1798,17 +1810,17 @@ describe('useQuery', () => {
1798
1810
  })
1799
1811
  // Set state
1800
1812
  expect(states[2]).toMatchObject({
1801
- data: 0,
1813
+ data: 99,
1802
1814
  isFetching: true,
1803
1815
  isSuccess: true,
1804
- isPreviousData: true,
1816
+ isPreviousData: false,
1805
1817
  })
1806
1818
  // Hook state update
1807
1819
  expect(states[3]).toMatchObject({
1808
- data: 0,
1820
+ data: 99,
1809
1821
  isFetching: true,
1810
1822
  isSuccess: true,
1811
- isPreviousData: true,
1823
+ isPreviousData: false,
1812
1824
  })
1813
1825
  // New data
1814
1826
  expect(states[4]).toMatchObject({
@@ -3733,6 +3745,61 @@ describe('useQuery', () => {
3733
3745
  expect(results[1]).toMatchObject({ data: 1, isFetching: false })
3734
3746
  })
3735
3747
 
3748
+ it('should show the correct data when switching keys with initialData, keepPreviousData & staleTime', async () => {
3749
+ const key = queryKey()
3750
+
3751
+ const ALL_TODOS = [
3752
+ { name: 'todo A', priority: 'high' },
3753
+ { name: 'todo B', priority: 'medium' },
3754
+ ]
3755
+
3756
+ const initialTodos = ALL_TODOS
3757
+
3758
+ function Page() {
3759
+ const [filter, setFilter] = React.useState('')
3760
+ const { data: todos } = useQuery(
3761
+ [...key, filter],
3762
+ async () => {
3763
+ return ALL_TODOS.filter((todo) =>
3764
+ filter ? todo.priority === filter : true,
3765
+ )
3766
+ },
3767
+ {
3768
+ initialData() {
3769
+ return filter === '' ? initialTodos : undefined
3770
+ },
3771
+ keepPreviousData: true,
3772
+ staleTime: 5000,
3773
+ },
3774
+ )
3775
+
3776
+ return (
3777
+ <div>
3778
+ Current Todos, filter: {filter || 'all'}
3779
+ <hr />
3780
+ <button onClick={() => setFilter('')}>All</button>
3781
+ <button onClick={() => setFilter('high')}>High</button>
3782
+ <ul>
3783
+ {(todos ?? []).map((todo) => (
3784
+ <li key={todo.name}>
3785
+ {todo.name} - {todo.priority}
3786
+ </li>
3787
+ ))}
3788
+ </ul>
3789
+ </div>
3790
+ )
3791
+ }
3792
+
3793
+ const rendered = renderWithClient(queryClient, <Page />)
3794
+
3795
+ await waitFor(() => rendered.getByText('Current Todos, filter: all'))
3796
+
3797
+ fireEvent.click(rendered.getByRole('button', { name: /high/i }))
3798
+ await waitFor(() => rendered.getByText('Current Todos, filter: high'))
3799
+ fireEvent.click(rendered.getByRole('button', { name: /all/i }))
3800
+ await waitFor(() => rendered.getByText('todo B - medium'))
3801
+ })
3802
+
3736
3803
  // // See https://github.com/tannerlinsley/react-query/issues/214
3737
3804
  it('data should persist when enabled is changed to false', async () => {
3738
3805
  const key = queryKey()