Skip to content

Commit f559d25

Browse files
committed
feat: add additional notify flags
1 parent 90d8e81 commit f559d25

File tree

5 files changed

+69
-24
lines changed

5 files changed

+69
-24
lines changed

docs/src/pages/reference/useQuery.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ const {
2626
initialData,
2727
isDataEqual,
2828
keepPreviousData,
29+
notifyOnFetchChange,
30+
notifyOnStaleChange,
2931
notifyOnStatusChange,
3032
onError,
3133
onSettled,
@@ -108,9 +110,17 @@ const result = useQuery({
108110
- If set to `true`, the query will refetch on reconnect if the data is stale.
109111
- If set to `false`, the query will not refetch on reconnect.
110112
- If set to `"always"`, the query will always refetch on reconnect.
113+
- `notifyOnFetchChange: boolean`
114+
- Optional
115+
- Set this to `false` to prevent re-renders when the `isFetching` or `failureCount` properties change.
116+
- Defaults to `true`.
117+
- `notifyOnStaleChange: boolean`
118+
- Optional
119+
- Set this to `true` to re-render when the `isStale` property changes.
120+
- Defaults to `false`.
111121
- `notifyOnStatusChange: boolean`
112122
- Optional
113-
- Set this to `false` to only re-render when there are changes to `data` or `error`.
123+
- Set this to `false` to prevent re-renders when the `status` property changes.
114124
- Defaults to `true`.
115125
- `onSuccess: (data: TData) => void`
116126
- Optional

src/core/queryObserver.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,10 @@ export class QueryObserver<
199199
protected fetch(
200200
fetchOptions?: ObserverFetchOptions
201201
): Promise<QueryObserverResult<TData, TError>> {
202-
const promise = this.getNextResult(fetchOptions)
203-
this.executeFetch(fetchOptions)
204-
return promise
202+
return this.executeFetch(fetchOptions).then(() => {
203+
this.updateResult()
204+
return this.currentResult
205+
})
205206
}
206207

207208
private optionalFetch(): void {
@@ -210,12 +211,14 @@ export class QueryObserver<
210211
}
211212
}
212213

213-
private executeFetch(fetchOptions?: ObserverFetchOptions): void {
214+
private executeFetch(
215+
fetchOptions?: ObserverFetchOptions
216+
): Promise<TQueryData | undefined> {
214217
// Make sure we reference the latest query as the current one might have been removed
215218
this.updateQuery()
216219

217220
// Fetch
218-
this.currentQuery
221+
return this.currentQuery
219222
.fetch(
220223
this.options as QueryOptions<TQueryData, TError, TQueryFnData>,
221224
fetchOptions
@@ -443,11 +446,19 @@ export class QueryObserver<
443446
}
444447

445448
if (
446-
// Always notify if notifyOnStatusChange is set
447-
this.options.notifyOnStatusChange !== false ||
448-
// Otherwise only notify on data or error change
449+
// Always notify on data or error changes
449450
currentResult.data !== prevResult.data ||
450-
currentResult.error !== prevResult.error
451+
currentResult.error !== prevResult.error ||
452+
// Maybe notify on status change
453+
(this.options.notifyOnStatusChange !== false &&
454+
currentResult.status !== prevResult.status) ||
455+
// Maybe notify on fetch change
456+
(this.options.notifyOnFetchChange !== false &&
457+
(currentResult.isFetching !== prevResult.isFetching ||
458+
currentResult.failureCount !== prevResult.failureCount)) ||
459+
// Maybe notify on stale change
460+
(this.options.notifyOnStaleChange &&
461+
currentResult.isStale !== prevResult.isStale)
451462
) {
452463
notifyOptions.listeners = true
453464
}

src/core/types.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,17 @@ export interface QueryObserverOptions<
125125
*/
126126
refetchOnMount?: boolean | 'always'
127127
/**
128-
* Whether a change to the query status should re-render a component.
129-
* If set to `false`, the component will only re-render when the actual `data` or `error` changes.
128+
* Whether a component should re-render when the `isFetching` or `failureCount` properties change.
129+
* Defaults to `true`.
130+
*/
131+
notifyOnFetchChange?: boolean
132+
/**
133+
* Whether a component should re-render when the `isStale` property changes.
134+
* Defaults to `false`.
135+
*/
136+
notifyOnStaleChange?: boolean
137+
/**
138+
* Whether a component should re-render when the `status` property changes.
130139
* Defaults to `true`.
131140
*/
132141
notifyOnStatusChange?: boolean

src/react/tests/useInfiniteQuery.test.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,16 @@ const fetchItems = async (
4141

4242
describe('useInfiniteQuery', () => {
4343
const queryCache = new QueryCache()
44-
const queryClient = new QueryClient({ queryCache })
44+
const queryClient = new QueryClient({
45+
queryCache,
46+
defaultOptions: {
47+
queries: {
48+
notifyOnFetchChange: true,
49+
notifyOnStaleChange: true,
50+
notifyOnStatusChange: true,
51+
},
52+
},
53+
})
4554

4655
it('should return the correct states for a successful query', async () => {
4756
const key = queryKey()
@@ -624,7 +633,7 @@ describe('useInfiniteQuery', () => {
624633

625634
await sleep(300)
626635

627-
expect(states.length).toBe(5)
636+
expect(states.length).toBe(4)
628637
expect(states[0]).toMatchObject({
629638
hasNextPage: undefined,
630639
data: undefined,
@@ -647,13 +656,6 @@ describe('useInfiniteQuery', () => {
647656
isSuccess: true,
648657
})
649658
expect(states[3]).toMatchObject({
650-
hasNextPage: true,
651-
data: { pages: [10] },
652-
isFetching: true,
653-
isFetchingNextPage: true,
654-
isSuccess: true,
655-
})
656-
expect(states[4]).toMatchObject({
657659
hasNextPage: true,
658660
data: { pages: [10, 11] },
659661
isFetching: false,

src/react/tests/useQuery.test.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@ import { useQuery, QueryClient, UseQueryResult, QueryCache } from '../..'
1414

1515
describe('useQuery', () => {
1616
const queryCache = new QueryCache()
17-
const queryClient = new QueryClient({ queryCache })
17+
const queryClient = new QueryClient({
18+
queryCache,
19+
defaultOptions: {
20+
queries: {
21+
notifyOnFetchChange: true,
22+
notifyOnStaleChange: true,
23+
notifyOnStatusChange: true,
24+
},
25+
},
26+
})
1827

1928
it('should return the correct types', () => {
2029
const key = queryKey()
@@ -508,13 +517,15 @@ describe('useQuery', () => {
508517
expect(states[1]).toMatchObject({ data: 'test' })
509518
})
510519

511-
it('should not re-render when notifyOnStatusChange is false and the selected data did not change', async () => {
520+
it('should not re-render when notify flags are false and the selected data did not change', async () => {
512521
const key = queryKey()
513522
const states: UseQueryResult<string>[] = []
514523

515524
function Page() {
516525
const state = useQuery(key, () => ({ name: 'test' }), {
517526
select: data => data.name,
527+
notifyOnFetchChange: false,
528+
notifyOnStaleChange: false,
518529
notifyOnStatusChange: false,
519530
})
520531

@@ -1353,7 +1364,7 @@ describe('useQuery', () => {
13531364
expect(fn).toHaveBeenCalledTimes(5)
13541365
})
13551366

1356-
it('should not re-render when a query status changes and notifyOnStatusChange is false', async () => {
1367+
it('should not re-render when a query status changes and notify flags are false', async () => {
13571368
const key = queryKey()
13581369
const states: UseQueryResult<string>[] = []
13591370

@@ -1366,6 +1377,8 @@ describe('useQuery', () => {
13661377
},
13671378
{
13681379
notifyOnStatusChange: false,
1380+
notifyOnFetchChange: false,
1381+
notifyOnStaleChange: false,
13691382
}
13701383
)
13711384

0 commit comments

Comments
 (0)