@tanstack/react-query 4.15.1 → 4.17.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.
|
|
3
|
+
"version": "4.17.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,8 +46,8 @@
|
|
|
46
46
|
"react-error-boundary": "^3.1.4"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"
|
|
50
|
-
"
|
|
49
|
+
"use-sync-external-store": "^1.2.0",
|
|
50
|
+
"@tanstack/query-core": "4.15.1"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { fireEvent, waitFor } from '@testing-library/react'
|
|
2
|
-
import { ErrorBoundary } from 'react-error-boundary'
|
|
3
2
|
import * as React from 'react'
|
|
4
|
-
|
|
5
|
-
import { createQueryClient, queryKey, renderWithClient, sleep } from './utils'
|
|
3
|
+
import { ErrorBoundary } from 'react-error-boundary'
|
|
6
4
|
import type { UseInfiniteQueryResult, UseQueryResult } from '..'
|
|
7
5
|
import {
|
|
8
6
|
QueryCache,
|
|
@@ -12,6 +10,7 @@ import {
|
|
|
12
10
|
useQuery,
|
|
13
11
|
useQueryErrorResetBoundary,
|
|
14
12
|
} from '..'
|
|
13
|
+
import { createQueryClient, queryKey, renderWithClient, sleep } from './utils'
|
|
15
14
|
|
|
16
15
|
describe("useQuery's in Suspense mode", () => {
|
|
17
16
|
const queryCache = new QueryCache()
|
|
@@ -1061,6 +1060,7 @@ describe('useQueries with suspense', () => {
|
|
|
1061
1060
|
<Page />
|
|
1062
1061
|
</React.Suspense>,
|
|
1063
1062
|
)
|
|
1063
|
+
|
|
1064
1064
|
await waitFor(() => rendered.getByText('loading'))
|
|
1065
1065
|
await waitFor(() => rendered.getByText('data: 1,2'))
|
|
1066
1066
|
|
|
@@ -1121,4 +1121,118 @@ describe('useQueries with suspense', () => {
|
|
|
1121
1121
|
|
|
1122
1122
|
expect(results).toEqual(['1', '2', 'loading'])
|
|
1123
1123
|
})
|
|
1124
|
+
|
|
1125
|
+
it("shouldn't unmount before all promises fetched", async () => {
|
|
1126
|
+
const key1 = queryKey()
|
|
1127
|
+
const key2 = queryKey()
|
|
1128
|
+
const results: string[] = []
|
|
1129
|
+
const refs: number[] = []
|
|
1130
|
+
|
|
1131
|
+
function Fallback() {
|
|
1132
|
+
results.push('loading')
|
|
1133
|
+
return <div>loading</div>
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
function Page() {
|
|
1137
|
+
const ref = React.useRef(Math.random())
|
|
1138
|
+
const result = useQueries({
|
|
1139
|
+
queries: [
|
|
1140
|
+
{
|
|
1141
|
+
queryKey: key1,
|
|
1142
|
+
queryFn: async () => {
|
|
1143
|
+
refs.push(ref.current)
|
|
1144
|
+
results.push('1')
|
|
1145
|
+
await sleep(10)
|
|
1146
|
+
return '1'
|
|
1147
|
+
},
|
|
1148
|
+
suspense: true,
|
|
1149
|
+
},
|
|
1150
|
+
{
|
|
1151
|
+
queryKey: key2,
|
|
1152
|
+
queryFn: async () => {
|
|
1153
|
+
refs.push(ref.current)
|
|
1154
|
+
results.push('2')
|
|
1155
|
+
await sleep(20)
|
|
1156
|
+
return '2'
|
|
1157
|
+
},
|
|
1158
|
+
suspense: true,
|
|
1159
|
+
},
|
|
1160
|
+
],
|
|
1161
|
+
})
|
|
1162
|
+
return (
|
|
1163
|
+
<div>
|
|
1164
|
+
<h1>data: {result.map((it) => it.data ?? 'null').join(',')}</h1>
|
|
1165
|
+
</div>
|
|
1166
|
+
)
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
const rendered = renderWithClient(
|
|
1170
|
+
queryClient,
|
|
1171
|
+
<React.Suspense fallback={<Fallback />}>
|
|
1172
|
+
<Page />
|
|
1173
|
+
</React.Suspense>,
|
|
1174
|
+
)
|
|
1175
|
+
await waitFor(() => rendered.getByText('loading'))
|
|
1176
|
+
expect(refs.length).toBe(2)
|
|
1177
|
+
await waitFor(() => rendered.getByText('data: 1,2'))
|
|
1178
|
+
expect(refs[0]).toBe(refs[1])
|
|
1179
|
+
})
|
|
1180
|
+
|
|
1181
|
+
it('should suspend all queries in parallel - global configuration', async () => {
|
|
1182
|
+
const queryClientSuspenseMode = createQueryClient({
|
|
1183
|
+
defaultOptions: {
|
|
1184
|
+
queries: {
|
|
1185
|
+
suspense: true,
|
|
1186
|
+
},
|
|
1187
|
+
},
|
|
1188
|
+
})
|
|
1189
|
+
const key1 = queryKey()
|
|
1190
|
+
const key2 = queryKey()
|
|
1191
|
+
const results: string[] = []
|
|
1192
|
+
|
|
1193
|
+
function Fallback() {
|
|
1194
|
+
results.push('loading')
|
|
1195
|
+
return <div>loading</div>
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
function Page() {
|
|
1199
|
+
const result = useQueries({
|
|
1200
|
+
queries: [
|
|
1201
|
+
{
|
|
1202
|
+
queryKey: key1,
|
|
1203
|
+
queryFn: async () => {
|
|
1204
|
+
results.push('1')
|
|
1205
|
+
await sleep(10)
|
|
1206
|
+
return '1'
|
|
1207
|
+
},
|
|
1208
|
+
},
|
|
1209
|
+
{
|
|
1210
|
+
queryKey: key2,
|
|
1211
|
+
queryFn: async () => {
|
|
1212
|
+
results.push('2')
|
|
1213
|
+
await sleep(20)
|
|
1214
|
+
return '2'
|
|
1215
|
+
},
|
|
1216
|
+
},
|
|
1217
|
+
],
|
|
1218
|
+
})
|
|
1219
|
+
return (
|
|
1220
|
+
<div>
|
|
1221
|
+
<h1>data: {result.map((it) => it.data ?? 'null').join(',')}</h1>
|
|
1222
|
+
</div>
|
|
1223
|
+
)
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
const rendered = renderWithClient(
|
|
1227
|
+
queryClientSuspenseMode,
|
|
1228
|
+
<React.Suspense fallback={<Fallback />}>
|
|
1229
|
+
<Page />
|
|
1230
|
+
</React.Suspense>,
|
|
1231
|
+
)
|
|
1232
|
+
|
|
1233
|
+
await waitFor(() => rendered.getByText('loading'))
|
|
1234
|
+
await waitFor(() => rendered.getByText('data: 1,2'))
|
|
1235
|
+
|
|
1236
|
+
expect(results).toEqual(['1', '2', 'loading'])
|
|
1237
|
+
})
|
|
1124
1238
|
})
|
|
@@ -1109,20 +1109,31 @@ describe('useInfiniteQuery', () => {
|
|
|
1109
1109
|
|
|
1110
1110
|
states.push(state)
|
|
1111
1111
|
|
|
1112
|
-
|
|
1112
|
+
return (
|
|
1113
|
+
<div>
|
|
1114
|
+
<div>page0: {state.data?.pages[0]}</div>
|
|
1115
|
+
<div>page1: {state.data?.pages[1]}</div>
|
|
1116
|
+
<button onClick={() => state.fetchNextPage({ pageParam: 5 })}>
|
|
1117
|
+
Fetch next page
|
|
1118
|
+
</button>
|
|
1119
|
+
</div>
|
|
1120
|
+
)
|
|
1121
|
+
}
|
|
1113
1122
|
|
|
1114
|
-
|
|
1115
|
-
setActTimeout(() => {
|
|
1116
|
-
fetchNextPage({ pageParam: 5 })
|
|
1117
|
-
}, 20)
|
|
1118
|
-
}, [fetchNextPage])
|
|
1123
|
+
const rendered = renderWithClient(queryClient, <Page />)
|
|
1119
1124
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1125
|
+
await waitFor(() => {
|
|
1126
|
+
rendered.getByText('page0: 0')
|
|
1127
|
+
})
|
|
1122
1128
|
|
|
1123
|
-
|
|
1129
|
+
fireEvent.click(rendered.getByRole('button', { name: 'Fetch next page' }))
|
|
1124
1130
|
|
|
1125
|
-
await
|
|
1131
|
+
await waitFor(() => {
|
|
1132
|
+
rendered.getByText('page1: 5')
|
|
1133
|
+
})
|
|
1134
|
+
|
|
1135
|
+
// make sure no additional renders are happening after fetching next page
|
|
1136
|
+
await sleep(20)
|
|
1126
1137
|
|
|
1127
1138
|
expect(states.length).toBe(4)
|
|
1128
1139
|
expect(states[0]).toMatchObject({
|
|
@@ -505,20 +505,26 @@ describe('useQuery', () => {
|
|
|
505
505
|
|
|
506
506
|
states.push(state)
|
|
507
507
|
|
|
508
|
-
|
|
508
|
+
return (
|
|
509
|
+
<div>
|
|
510
|
+
<div>isSuccess: {state.isSuccess ? 'true' : 'false'}</div>
|
|
511
|
+
<button onClick={() => state.refetch()}>refetch</button>
|
|
512
|
+
</div>
|
|
513
|
+
)
|
|
514
|
+
}
|
|
509
515
|
|
|
510
|
-
|
|
511
|
-
setActTimeout(() => {
|
|
512
|
-
refetch()
|
|
513
|
-
}, 10)
|
|
514
|
-
}, [refetch])
|
|
516
|
+
const rendered = renderWithClient(queryClient, <Page />)
|
|
515
517
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
+
await waitFor(() => {
|
|
519
|
+
rendered.getByText('isSuccess: false')
|
|
520
|
+
})
|
|
518
521
|
|
|
519
|
-
|
|
522
|
+
fireEvent.click(rendered.getByRole('button', { name: 'refetch' }))
|
|
523
|
+
|
|
524
|
+
await waitFor(() => {
|
|
525
|
+
rendered.getByText('isSuccess: true')
|
|
526
|
+
})
|
|
520
527
|
|
|
521
|
-
await sleep(50)
|
|
522
528
|
expect(onSuccess).toHaveBeenCalledTimes(1)
|
|
523
529
|
expect(onSuccess).toHaveBeenCalledWith('data')
|
|
524
530
|
})
|
|
@@ -622,12 +628,16 @@ describe('useQuery', () => {
|
|
|
622
628
|
function Page() {
|
|
623
629
|
const state = useQuery(key, () => 'data', { onSettled })
|
|
624
630
|
states.push(state)
|
|
625
|
-
|
|
631
|
+
|
|
632
|
+
return <div>data: {state.data}</div>
|
|
626
633
|
}
|
|
627
634
|
|
|
628
|
-
renderWithClient(queryClient, <Page />)
|
|
635
|
+
const rendered = renderWithClient(queryClient, <Page />)
|
|
636
|
+
|
|
637
|
+
await waitFor(() => {
|
|
638
|
+
rendered.getByText('data: data')
|
|
639
|
+
})
|
|
629
640
|
|
|
630
|
-
await sleep(10)
|
|
631
641
|
expect(states.length).toBe(2)
|
|
632
642
|
expect(onSettled).toHaveBeenCalledTimes(1)
|
|
633
643
|
expect(onSettled).toHaveBeenCalledWith('data', null)
|
|
@@ -1062,12 +1072,15 @@ describe('useQuery', () => {
|
|
|
1062
1072
|
},
|
|
1063
1073
|
})
|
|
1064
1074
|
states.push(state)
|
|
1065
|
-
|
|
1075
|
+
|
|
1076
|
+
return <div>{state.status}</div>
|
|
1066
1077
|
}
|
|
1067
1078
|
|
|
1068
|
-
renderWithClient(queryClient, <Page />)
|
|
1079
|
+
const rendered = renderWithClient(queryClient, <Page />)
|
|
1069
1080
|
|
|
1070
|
-
await
|
|
1081
|
+
await waitFor(() => {
|
|
1082
|
+
rendered.getByText('error')
|
|
1083
|
+
})
|
|
1071
1084
|
|
|
1072
1085
|
expect(mockLogger.error).toHaveBeenCalledWith(error)
|
|
1073
1086
|
expect(states.length).toBe(2)
|
|
@@ -1175,7 +1188,13 @@ describe('useQuery', () => {
|
|
|
1175
1188
|
|
|
1176
1189
|
renderWithClient(queryClient, <Page />)
|
|
1177
1190
|
|
|
1178
|
-
await
|
|
1191
|
+
await waitFor(() => {
|
|
1192
|
+
expect(renderCount).toBe(2)
|
|
1193
|
+
})
|
|
1194
|
+
|
|
1195
|
+
// give it a bit more time to make sure no additional renders are triggered
|
|
1196
|
+
await sleep(20)
|
|
1197
|
+
|
|
1179
1198
|
expect(renderCount).toBe(2)
|
|
1180
1199
|
expect(states.length).toBe(2)
|
|
1181
1200
|
expect(states[0]).toMatchObject({ data: undefined })
|
|
@@ -2482,12 +2501,14 @@ describe('useQuery', () => {
|
|
|
2482
2501
|
function Page() {
|
|
2483
2502
|
const state = useQuery([key, variables], queryFn)
|
|
2484
2503
|
states.push(state)
|
|
2485
|
-
return
|
|
2504
|
+
return <div>{state.status}</div>
|
|
2486
2505
|
}
|
|
2487
2506
|
|
|
2488
|
-
renderWithClient(queryClient, <Page />)
|
|
2507
|
+
const rendered = renderWithClient(queryClient, <Page />)
|
|
2489
2508
|
|
|
2490
|
-
await
|
|
2509
|
+
await waitFor(() => {
|
|
2510
|
+
rendered.getByText('success')
|
|
2511
|
+
})
|
|
2491
2512
|
|
|
2492
2513
|
expect(states[1]?.data).toEqual([key, variables])
|
|
2493
2514
|
})
|
|
@@ -5461,13 +5482,15 @@ describe('useQuery', () => {
|
|
|
5461
5482
|
onlineMock.mockReturnValue(true)
|
|
5462
5483
|
window.dispatchEvent(new Event('online'))
|
|
5463
5484
|
|
|
5464
|
-
await
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5485
|
+
await waitFor(() => {
|
|
5486
|
+
expect(queryClient.getQueryState(key)).toMatchObject({
|
|
5487
|
+
fetchStatus: 'idle',
|
|
5488
|
+
status: 'success',
|
|
5489
|
+
})
|
|
5469
5490
|
})
|
|
5470
5491
|
|
|
5492
|
+
// give it a bit more time to make sure queryFn is not called again
|
|
5493
|
+
await sleep(15)
|
|
5471
5494
|
expect(count).toBe(1)
|
|
5472
5495
|
|
|
5473
5496
|
onlineMock.mockRestore()
|