Skip to content

Commit e29ae76

Browse files
authored
Merge pull request #3 from tannerlinsley/master
update
2 parents 7e7d2d3 + a88d80f commit e29ae76

File tree

11 files changed

+205
-66
lines changed

11 files changed

+205
-66
lines changed

docs/src/components/markdown.module.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@
156156
@apply text-xl;
157157
}
158158

159+
.markdown > h2 > a,
160+
.markdown > h3 > a,
161+
.markdown > h4 > a {
162+
@apply underline;
163+
}
164+
159165
.markdown > .markdown ul {
160166
@apply list-disc;
161167
}

docs/src/pages/guides/infinite-queries.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ Manually removing a single value from an individual page:
160160
```js
161161
const newPagesArray = []
162162
oldPagesArray?.pages.forEach(page => {
163-
const newData = page.data.filter(val => val.id !== updatedId)
164-
newPagesArray.push({ data: newData, pageParam: page.pageParam })
163+
const newData = page.filter(val => val.id !== updatedId)
164+
newPagesArray.push(newData)
165165
})
166166
queryClient.setQueryData('projects', data => ({
167167
pages: newPagesArray,

docs/src/pages/guides/migrating-to-react-query-3.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,37 @@ setConsole({
416416

417417
In version 3 **this is done automatically when React Query is used in React Native**.
418418

419+
420+
### Typescript
421+
#### `QueryStatus` has been changed from an [enum](https://www.typescriptlang.org/docs/handbook/enums.html#string-enums) to a [union type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types)
422+
423+
So, if you were checking the status property of a query or mutation against a QueryStatus enum property you will have to check it now against the string literal the enum previously held for each property.
424+
425+
Therefore you have to change the enum properties to their equivalent string literal, like this:
426+
- `QueryStatus.Idle` -> `'idle'`
427+
- `QueryStatus.Loading` -> `'loading'`
428+
- `QueryStatus.Error` -> `'error'`
429+
- `QueryStatus.Success` -> `'success'`
430+
431+
Here is an example of the changes you would have to make:
432+
433+
```diff
434+
- import { useQuery, QueryStatus } from 'react-query';
435+
+ import { useQuery } from 'react-query';
436+
437+
const { data, status } = useQuery(['post', id], () => fetchPost(id))
438+
439+
- if (status === QueryStatus.Loading) {
440+
+ if (status === 'loading') {
441+
...
442+
}
443+
444+
- if (status === QueryStatus.Error) {
445+
+ if (status === 'error') {
446+
...
447+
}
448+
```
449+
419450
## New features
420451

421452
#### Query Data Selectors

docs/src/pages/guides/paginated-queries.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ However, if you run this simple example, you might notice something strange:
1313

1414
**The UI jumps in and out of the `success` and `loading` states because each new page is treated like a brand new query.**
1515

16-
This experience is not optimal and unfortunately is how many tools today insist on working. But not React Query! As you may have guessed, React Query comes with an awesome featured called `keepPreviousData` that allows us to get around this.
16+
This experience is not optimal and unfortunately is how many tools today insist on working. But not React Query! As you may have guessed, React Query comes with an awesome feature called `keepPreviousData` that allows us to get around this.
1717

1818
## Better Paginated Queries with `keepPreviousData`
1919

docs/src/pages/guides/updates-from-mutation-responses.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ mutation.mutate({
1919

2020
// The query below will be updated with the response from the
2121
// successful mutation
22-
const { status, data, error } = useQuery(['todo', { id: 5 }], fetchTodoByID)
22+
const { status, data, error } = useQuery(['todo', { id: 5 }], fetchTodoById)
2323
```
2424

2525
You might want to tie the `onSuccess` logic into a reusable mutation, for that you can

src/core/queryClient.ts

Lines changed: 75 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -252,24 +252,24 @@ export class QueryClient {
252252
return promise
253253
}
254254

255-
fetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData>(
256-
options: FetchQueryOptions<TQueryFnData, TError, TData>
255+
fetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
256+
options: FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>
257257
): Promise<TData>
258-
fetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData>(
259-
queryKey: QueryKey,
260-
options?: FetchQueryOptions<TQueryFnData, TError, TData>
258+
fetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
259+
queryKey: TQueryKey,
260+
options?: FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>
261261
): Promise<TData>
262-
fetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData>(
263-
queryKey: QueryKey,
264-
queryFn: QueryFunction<TQueryFnData>,
265-
options?: FetchQueryOptions<TQueryFnData, TError, TData>
262+
fetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
263+
queryKey: TQueryKey,
264+
queryFn: QueryFunction<TQueryFnData, TQueryKey>,
265+
options?: FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>
266266
): Promise<TData>
267-
fetchQuery<TQueryFnData, TError, TData = TQueryFnData>(
268-
arg1: QueryKey | FetchQueryOptions<TQueryFnData, TError, TData>,
267+
fetchQuery<TQueryFnData, TError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
268+
arg1: TQueryKey | FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
269269
arg2?:
270-
| QueryFunction<TQueryFnData>
271-
| FetchQueryOptions<TQueryFnData, TError, TData>,
272-
arg3?: FetchQueryOptions<TQueryFnData, TError, TData>
270+
| QueryFunction<TQueryFnData, TQueryKey>
271+
| FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
272+
arg3?: FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>
273273
): Promise<TData> {
274274
const parsedOptions = parseQueryArgs(arg1, arg2, arg3)
275275
const defaultedOptions = this.defaultQueryOptions(parsedOptions)
@@ -286,22 +286,22 @@ export class QueryClient {
286286
: Promise.resolve(query.state.data as TData)
287287
}
288288

289-
prefetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData>(
290-
options: FetchQueryOptions<TQueryFnData, TError, TData>
289+
prefetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
290+
options: FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>
291291
): Promise<void>
292-
prefetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData>(
293-
queryKey: QueryKey,
294-
options?: FetchQueryOptions<TQueryFnData, TError, TData>
292+
prefetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
293+
queryKey: TQueryKey,
294+
options?: FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>
295295
): Promise<void>
296-
prefetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData>(
297-
queryKey: QueryKey,
298-
queryFn: QueryFunction,
299-
options?: FetchQueryOptions<TQueryFnData, TError, TData>
296+
prefetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
297+
queryKey: TQueryKey,
298+
queryFn: QueryFunction<TQueryFnData, TQueryKey>,
299+
options?: FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>
300300
): Promise<void>
301-
prefetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData>(
302-
arg1: QueryKey | FetchQueryOptions<TQueryFnData, TError, TData>,
303-
arg2?: QueryFunction | FetchQueryOptions<TQueryFnData, TError, TData>,
304-
arg3?: FetchQueryOptions<TQueryFnData, TError, TData>
301+
prefetchQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
302+
arg1: TQueryKey | FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
303+
arg2?: QueryFunction<TQueryFnData, TQueryKey> | FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
304+
arg3?: FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey>
305305
): Promise<void> {
306306
return this.fetchQuery(arg1 as any, arg2 as any, arg3)
307307
.then(noop)
@@ -311,33 +311,36 @@ export class QueryClient {
311311
fetchInfiniteQuery<
312312
TQueryFnData = unknown,
313313
TError = unknown,
314-
TData = TQueryFnData
314+
TData = TQueryFnData,
315+
TQueryKey extends QueryKey = QueryKey
315316
>(
316-
options: FetchInfiniteQueryOptions<TQueryFnData, TError, TData>
317+
options: FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>
317318
): Promise<InfiniteData<TData>>
318319
fetchInfiniteQuery<
319320
TQueryFnData = unknown,
320321
TError = unknown,
321-
TData = TQueryFnData
322+
TData = TQueryFnData,
323+
TQueryKey extends QueryKey = QueryKey
322324
>(
323-
queryKey: QueryKey,
324-
options?: FetchInfiniteQueryOptions<TQueryFnData, TError, TData>
325+
queryKey: TQueryKey,
326+
options?: FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>
325327
): Promise<InfiniteData<TData>>
326328
fetchInfiniteQuery<
327329
TQueryFnData = unknown,
328330
TError = unknown,
329-
TData = TQueryFnData
331+
TData = TQueryFnData,
332+
TQueryKey extends QueryKey = QueryKey
330333
>(
331-
queryKey: QueryKey,
332-
queryFn: QueryFunction<TQueryFnData>,
333-
options?: FetchInfiniteQueryOptions<TQueryFnData, TError, TData>
334+
queryKey: TQueryKey,
335+
queryFn: QueryFunction<TQueryFnData, TQueryKey>,
336+
options?: FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>
334337
): Promise<InfiniteData<TData>>
335-
fetchInfiniteQuery<TQueryFnData, TError, TData = TQueryFnData>(
336-
arg1: QueryKey | FetchInfiniteQueryOptions<TQueryFnData, TError, TData>,
338+
fetchInfiniteQuery<TQueryFnData, TError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
339+
arg1: TQueryKey | FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
337340
arg2?:
338-
| QueryFunction<TQueryFnData>
339-
| FetchInfiniteQueryOptions<TQueryFnData, TError, TData>,
340-
arg3?: FetchInfiniteQueryOptions<TQueryFnData, TError, TData>
341+
| QueryFunction<TQueryFnData, TQueryKey>
342+
| FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
343+
arg3?: FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>
341344
): Promise<InfiniteData<TData>> {
342345
const parsedOptions = parseQueryArgs(arg1, arg2, arg3)
343346
parsedOptions.behavior = infiniteQueryBehavior<
@@ -348,20 +351,39 @@ export class QueryClient {
348351
return this.fetchQuery(parsedOptions)
349352
}
350353

351-
prefetchInfiniteQuery(options: FetchInfiniteQueryOptions): Promise<void>
352-
prefetchInfiniteQuery(
353-
queryKey: QueryKey,
354-
options?: FetchInfiniteQueryOptions
354+
prefetchInfiniteQuery<
355+
TQueryFnData = unknown,
356+
TError = unknown,
357+
TData = TQueryFnData,
358+
TQueryKey extends QueryKey = QueryKey
359+
>(
360+
options: FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>
355361
): Promise<void>
356-
prefetchInfiniteQuery(
357-
queryKey: QueryKey,
358-
queryFn: QueryFunction,
359-
options?: FetchInfiniteQueryOptions
362+
prefetchInfiniteQuery<
363+
TQueryFnData = unknown,
364+
TError = unknown,
365+
TData = TQueryFnData,
366+
TQueryKey extends QueryKey = QueryKey
367+
>(
368+
queryKey: TQueryKey,
369+
options?: FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>
360370
): Promise<void>
361-
prefetchInfiniteQuery(
362-
arg1: QueryKey | FetchInfiniteQueryOptions,
363-
arg2?: QueryFunction | FetchInfiniteQueryOptions,
364-
arg3?: FetchInfiniteQueryOptions
371+
prefetchInfiniteQuery<
372+
TQueryFnData = unknown,
373+
TError = unknown,
374+
TData = TQueryFnData,
375+
TQueryKey extends QueryKey = QueryKey
376+
>(
377+
queryKey: TQueryKey,
378+
queryFn: QueryFunction<TQueryFnData, TQueryKey>,
379+
options?: FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>
380+
): Promise<void>
381+
prefetchInfiniteQuery<TQueryFnData, TError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(
382+
arg1: TQueryKey | FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
383+
arg2?:
384+
| QueryFunction<TQueryFnData, TQueryKey>
385+
| FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
386+
arg3?: FetchInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey>
365387
): Promise<void> {
366388
return this.fetchInfiniteQuery(arg1 as any, arg2 as any, arg3)
367389
.then(noop)

src/core/tests/queryClient.test.tsx

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { sleep, queryKey, mockConsoleError } from '../../react/tests/utils'
2-
import { QueryCache, QueryClient, QueryObserver } from '../..'
2+
import { QueryCache, QueryClient, QueryFunction, QueryObserver } from '../..'
33

44
describe('queryClient', () => {
55
let queryClient: QueryClient
@@ -186,6 +186,23 @@ describe('queryClient', () => {
186186
})
187187

188188
describe('fetchQuery', () => {
189+
test('should not type-error with strict query key', async () => {
190+
type StrictData = 'data'
191+
type StrictQueryKey = ['strict', string]
192+
const key: StrictQueryKey = ['strict', queryKey()]
193+
194+
const fetchFn: QueryFunction<StrictData, StrictQueryKey> = () => (
195+
Promise.resolve('data')
196+
)
197+
198+
await expect(
199+
queryClient.fetchQuery<StrictData, any, StrictData, StrictQueryKey>(
200+
key,
201+
fetchFn,
202+
)
203+
).resolves.toEqual('data')
204+
})
205+
189206
// https://github.com/tannerlinsley/react-query/issues/652
190207
test('should not retry by default', async () => {
191208
const consoleMock = mockConsoleError()
@@ -282,6 +299,28 @@ describe('queryClient', () => {
282299
})
283300

284301
describe('fetchInfiniteQuery', () => {
302+
test('should not type-error with strict query key', async () => {
303+
type StrictData = string
304+
type StrictQueryKey = ['strict', string]
305+
const key: StrictQueryKey = ['strict', queryKey()]
306+
307+
const data = {
308+
pages: ['data'],
309+
pageParams: [undefined],
310+
}
311+
312+
const fetchFn: QueryFunction<StrictData, StrictQueryKey> = () => (
313+
Promise.resolve(data.pages[0])
314+
)
315+
316+
await expect(
317+
queryClient.fetchInfiniteQuery<StrictData, any, StrictData, StrictQueryKey>(
318+
key,
319+
fetchFn,
320+
)
321+
).resolves.toEqual(data)
322+
})
323+
285324
test('should return infinite query data', async () => {
286325
const key = queryKey()
287326
const result = await queryClient.fetchInfiniteQuery(
@@ -301,6 +340,25 @@ describe('queryClient', () => {
301340
})
302341

303342
describe('prefetchInfiniteQuery', () => {
343+
test('should not type-error with strict query key', async () => {
344+
type StrictData = 'data'
345+
type StrictQueryKey = ['strict', string]
346+
const key: StrictQueryKey = ['strict', queryKey()]
347+
348+
const fetchFn: QueryFunction<StrictData, StrictQueryKey> = () => (
349+
Promise.resolve('data')
350+
)
351+
352+
await queryClient.prefetchInfiniteQuery<StrictData, any, StrictData, StrictQueryKey>(key, fetchFn)
353+
354+
const result = queryClient.getQueryData(key)
355+
356+
expect(result).toEqual({
357+
pages: ['data'],
358+
pageParams: [undefined],
359+
})
360+
})
361+
304362
test('should return infinite query data', async () => {
305363
const key = queryKey()
306364

@@ -318,6 +376,22 @@ describe('queryClient', () => {
318376
})
319377

320378
describe('prefetchQuery', () => {
379+
test('should not type-error with strict query key', async () => {
380+
type StrictData = 'data'
381+
type StrictQueryKey = ['strict', string]
382+
const key: StrictQueryKey = ['strict', queryKey()]
383+
384+
const fetchFn: QueryFunction<StrictData, StrictQueryKey> = () => (
385+
Promise.resolve('data')
386+
)
387+
388+
await queryClient.prefetchQuery<StrictData, any, StrictData, StrictQueryKey>(key, fetchFn);
389+
390+
const result = queryClient.getQueryData(key);
391+
392+
expect(result).toEqual('data')
393+
})
394+
321395
test('should return undefined when an error is thrown', async () => {
322396
const consoleMock = mockConsoleError()
323397

src/core/tests/queryObserver.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ describe('queryObserver', () => {
241241
})
242242

243243
test('should always run the selector again if selector throws an error', async () => {
244+
const consoleMock = mockConsoleError()
244245
const key = queryKey()
245246
const results: QueryObserverResult[] = []
246247
const select = () => {
@@ -284,6 +285,7 @@ describe('queryObserver', () => {
284285
isFetching: false,
285286
data: undefined,
286287
})
288+
consoleMock.mockRestore()
287289
})
288290

289291
test('should structurally share the selector', async () => {

0 commit comments

Comments
 (0)