@tanstack/react-query 4.13.5 → 4.14.0
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/build/lib/QueryClientProvider.esm.js +5 -0
- package/build/lib/QueryClientProvider.esm.js.map +1 -1
- package/build/lib/QueryClientProvider.js +5 -0
- package/build/lib/QueryClientProvider.js.map +1 -1
- package/build/lib/QueryClientProvider.mjs +5 -0
- package/build/lib/QueryClientProvider.mjs.map +1 -1
- package/build/umd/index.development.js +16 -3
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/QueryClientProvider.tsx +8 -0
- package/src/__tests__/ssr-hydration.test.tsx +24 -4
- package/src/__tests__/useQuery.test.tsx +80 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-query",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.14.0",
|
|
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.
|
|
49
|
+
"@tanstack/query-core": "4.14.0",
|
|
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,
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
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(() =>
|
|
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:
|
|
1813
|
+
data: 99,
|
|
1802
1814
|
isFetching: true,
|
|
1803
1815
|
isSuccess: true,
|
|
1804
|
-
isPreviousData:
|
|
1816
|
+
isPreviousData: false,
|
|
1805
1817
|
})
|
|
1806
1818
|
// Hook state update
|
|
1807
1819
|
expect(states[3]).toMatchObject({
|
|
1808
|
-
data:
|
|
1820
|
+
data: 99,
|
|
1809
1821
|
isFetching: true,
|
|
1810
1822
|
isSuccess: true,
|
|
1811
|
-
isPreviousData:
|
|
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()
|