Skip to content

Commit c47f415

Browse files
committed
feat: add errorUpdatedAt property
1 parent 9cef1ea commit c47f415

File tree

10 files changed

+36
-23
lines changed

10 files changed

+36
-23
lines changed

docs/src/pages/guides/initial-query-data.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ function Todo({ todoId }) {
7171
}
7272
```
7373
74-
Most of the time, this pattern works well, but if the source query you're using to look up the initial data from is old, you may not want to use the data at all and just fetch from the server. To make this decision easier, you can use the `queryClient.getQueryState` method instead to get more information about the source query, including a `state.updatedAt` timestamp you can use to decide if the query is "fresh" enough for your needs:
74+
Most of the time, this pattern works well, but if the source query you're using to look up the initial data from is old, you may not want to use the data at all and just fetch from the server. To make this decision easier, you can use the `queryClient.getQueryState` method instead to get more information about the source query, including a `state.dataUpdatedAt` timestamp you can use to decide if the query is "fresh" enough for your needs:
7575
7676
```js
7777
function Todo({ todoId }) {
@@ -81,7 +81,7 @@ function Todo({ todoId }) {
8181
const state = queryClient.getQueryState('todos')
8282

8383
// If the query exists and has data that is no older than 10 seconds...
84-
if (state && Date.now() - state.updatedAt <= 10 * 1000) {
84+
if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) {
8585
// return the individual todo
8686
return state.data.find(d => d.id === todoId)
8787
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,10 @@ Parameters can still be filtered within the query function itself as the `QueryF
324324
325325
The `QueryResult.clear()` method has been renamed to `QueryResult.remove()`.
326326
327+
### QueryResult.updatedAt
328+
329+
Because data and errors can be present at the same time, the `updatedAt` property has been split into `dataUpdatedAt` and `errorUpdatedAt`.
330+
327331
### setConsole
328332
329333
The `setConsole` function has been replaced by `setLogger`:

docs/src/pages/guides/ssr.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ The setup is minimal and this can be a quick solution for some cases, but there
4141

4242
- If you are calling `useQuery` in a component deeper down in the tree you need to pass the `initialData` down to that point
4343
- If you are calling `useQuery` with the same query in multiple locations, you need to pass `initialData` to all of them
44-
- There is no way to know at what time the query was fetched on the server, so `updatedAt` and determining if the query needs refetching is based on when the page loaded instead
44+
- There is no way to know at what time the query was fetched on the server, so `dataUpdatedAt` and determining if the query needs refetching is based on when the page loaded instead
4545

4646
### Using Hydration
4747

@@ -186,7 +186,7 @@ Sometimes this behavior is not desirable, maybe you want to render an error page
186186

187187
### Staleness is measured from when the query was fetched on the server
188188

189-
A query is considered stale depending on when it was `updatedAt`. A caveat here is that the server needs to have the correct time for this to work properly, but UTC time is used, so timezones do not factor into this.
189+
A query is considered stale depending on when it was `dataUpdatedAt`. A caveat here is that the server needs to have the correct time for this to work properly, but UTC time is used, so timezones do not factor into this.
190190

191191
Because `staleTime` defaults to `0`, queries will be refetched in the background on page load by default. You might want to use a higher `staleTime` to avoid this double fetching, especially if you don't cache your markup.
192192

docs/src/pages/reference/QueryCache.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Its available methods are:
2525

2626
`find` is a slightly more advanced synchronous method that can be used to get an existing query instance from the cache. This instance not only contains **all** the state for the query, but all of the instances, and underlying guts of the query as well. If the query does not exist, `undefined` will be returned.
2727

28-
> Note: This is not typically needed for most applications, but can come in handy when needing more information about a query in rare scenarios (eg. Looking at the query.state.updatedAt timestamp to decide whether a query is fresh enough to be used as an initial value)
28+
> Note: This is not typically needed for most applications, but can come in handy when needing more information about a query in rare scenarios (eg. Looking at the query.state.dataUpdatedAt timestamp to decide whether a query is fresh enough to be used as an initial value)
2929
3030
```js
3131
const query = queryCache.find(queryKey)

docs/src/pages/reference/QueryClient.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ setQueryData(queryKey, oldData => newData)
169169

170170
```js
171171
const state = queryClient.getQueryState(queryKey)
172-
console.log(state.updatedAt)
172+
console.log(state.dataUpdatedAt)
173173
```
174174

175175
**Options**

src/core/query.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ interface FetchAction {
8383
interface SuccessAction<TData> {
8484
data: TData | undefined
8585
type: 'success'
86-
updatedAt?: number
86+
dataUpdatedAt?: number
8787
}
8888

8989
interface ErrorAction<TError> {
@@ -201,7 +201,7 @@ export class Query<TData = unknown, TError = unknown, TQueryFnData = TData> {
201201
this.dispatch({
202202
data,
203203
type: 'success',
204-
updatedAt: options?.updatedAt,
204+
dataUpdatedAt: options?.updatedAt,
205205
})
206206

207207
return data
@@ -483,7 +483,7 @@ export class Query<TData = unknown, TError = unknown, TQueryFnData = TData> {
483483
...state,
484484
data: action.data,
485485
dataUpdateCount: state.dataUpdateCount + 1,
486-
dataUpdatedAt: action.updatedAt ?? Date.now(),
486+
dataUpdatedAt: action.dataUpdatedAt ?? Date.now(),
487487
error: null,
488488
fetchFailureCount: 0,
489489
isFetching: false,

src/core/queryObserver.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ export class QueryObserver<
268268
}
269269

270270
const time = timeUntilStale(
271-
this.currentResult.updatedAt,
271+
this.currentResult.dataUpdatedAt,
272272
this.options.staleTime
273273
)
274274

@@ -336,7 +336,7 @@ export class QueryObserver<
336336
let isPreviousData = false
337337
let isPlaceholderData = false
338338
let data: TData | undefined
339-
let updatedAt = state.dataUpdatedAt
339+
let dataUpdatedAt = state.dataUpdatedAt
340340

341341
// Optimistically set status to loading if we will start fetching
342342
if (willFetch) {
@@ -353,7 +353,7 @@ export class QueryObserver<
353353
this.previousQueryResult?.isSuccess
354354
) {
355355
data = this.previousQueryResult.data
356-
updatedAt = this.previousQueryResult.updatedAt
356+
dataUpdatedAt = this.previousQueryResult.dataUpdatedAt
357357
status = this.previousQueryResult.status
358358
isPreviousData = true
359359
}
@@ -394,7 +394,9 @@ export class QueryObserver<
394394
const result: QueryObserverBaseResult<TData, TError> = {
395395
...getStatusProps(status),
396396
data,
397+
dataUpdatedAt,
397398
error: state.error,
399+
errorUpdatedAt: state.errorUpdateCount,
398400
failureCount: state.fetchFailureCount,
399401
isFetched: state.dataUpdateCount > 0,
400402
isFetchedAfterMount: state.dataUpdateCount > this.initialDataUpdateCount,
@@ -406,7 +408,6 @@ export class QueryObserver<
406408
isStale: this.isStale(),
407409
refetch: this.refetch,
408410
remove: this.remove,
409-
updatedAt,
410411
}
411412

412413
return result as QueryObserverResult<TData, TError>

src/core/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ export type QueryStatus = 'idle' | 'loading' | 'error' | 'success'
225225

226226
export interface QueryObserverBaseResult<TData = unknown, TError = unknown> {
227227
data: TData | undefined
228+
dataUpdatedAt: number
228229
error: TError | null
230+
errorUpdatedAt: number
229231
failureCount: number
230232
isError: boolean
231233
isFetched: boolean
@@ -244,7 +246,6 @@ export interface QueryObserverBaseResult<TData = unknown, TError = unknown> {
244246
) => Promise<QueryObserverResult<TData, TError>>
245247
remove: () => void
246248
status: QueryStatus
247-
updatedAt: number
248249
}
249250

250251
export interface QueryObserverIdleResult<TData = unknown, TError = unknown>

src/react/tests/useInfiniteQuery.test.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ describe('useInfiniteQuery', () => {
7373
expect(states.length).toBe(2)
7474
expect(states[0]).toEqual({
7575
data: undefined,
76+
dataUpdatedAt: 0,
7677
error: null,
78+
errorUpdatedAt: 0,
7779
failureCount: 0,
7880
fetchNextPage: expect.any(Function),
7981
fetchPreviousPage: expect.any(Function),
@@ -96,12 +98,13 @@ describe('useInfiniteQuery', () => {
9698
refetch: expect.any(Function),
9799
remove: expect.any(Function),
98100
status: 'loading',
99-
updatedAt: expect.any(Number),
100101
})
101102

102103
expect(states[1]).toEqual({
103104
data: { pages: [0], pageParams: [undefined] },
105+
dataUpdatedAt: expect.any(Number),
104106
error: null,
107+
errorUpdatedAt: 0,
105108
failureCount: 0,
106109
fetchNextPage: expect.any(Function),
107110
fetchPreviousPage: expect.any(Function),
@@ -124,7 +127,6 @@ describe('useInfiniteQuery', () => {
124127
refetch: expect.any(Function),
125128
remove: expect.any(Function),
126129
status: 'success',
127-
updatedAt: expect.any(Number),
128130
})
129131
})
130132

src/react/tests/useQuery.test.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ describe('useQuery', () => {
123123

124124
expect(states[0]).toEqual({
125125
data: undefined,
126+
dataUpdatedAt: 0,
126127
error: null,
128+
errorUpdatedAt: 0,
127129
failureCount: 0,
128130
isError: false,
129131
isFetched: false,
@@ -140,12 +142,13 @@ describe('useQuery', () => {
140142
refetch: expect.any(Function),
141143
remove: expect.any(Function),
142144
status: 'loading',
143-
updatedAt: expect.any(Number),
144145
})
145146

146147
expect(states[1]).toEqual({
147148
data: 'test',
149+
dataUpdatedAt: expect.any(Number),
148150
error: null,
151+
errorUpdatedAt: 0,
149152
failureCount: 0,
150153
isError: false,
151154
isFetched: true,
@@ -162,7 +165,6 @@ describe('useQuery', () => {
162165
refetch: expect.any(Function),
163166
remove: expect.any(Function),
164167
status: 'success',
165-
updatedAt: expect.any(Number),
166168
})
167169
})
168170

@@ -197,7 +199,9 @@ describe('useQuery', () => {
197199

198200
expect(states[0]).toEqual({
199201
data: undefined,
202+
dataUpdatedAt: 0,
200203
error: null,
204+
errorUpdatedAt: 0,
201205
failureCount: 0,
202206
isError: false,
203207
isFetched: false,
@@ -214,12 +218,13 @@ describe('useQuery', () => {
214218
refetch: expect.any(Function),
215219
remove: expect.any(Function),
216220
status: 'loading',
217-
updatedAt: expect.any(Number),
218221
})
219222

220223
expect(states[1]).toEqual({
221224
data: undefined,
225+
dataUpdatedAt: 0,
222226
error: null,
227+
errorUpdatedAt: 0,
223228
failureCount: 1,
224229
isError: false,
225230
isFetched: false,
@@ -236,12 +241,13 @@ describe('useQuery', () => {
236241
refetch: expect.any(Function),
237242
remove: expect.any(Function),
238243
status: 'loading',
239-
updatedAt: expect.any(Number),
240244
})
241245

242246
expect(states[2]).toEqual({
243247
data: undefined,
248+
dataUpdatedAt: 0,
244249
error: 'rejected',
250+
errorUpdatedAt: expect.any(Number),
245251
failureCount: 2,
246252
isError: true,
247253
isFetched: false,
@@ -258,7 +264,6 @@ describe('useQuery', () => {
258264
refetch: expect.any(Function),
259265
remove: expect.any(Function),
260266
status: 'error',
261-
updatedAt: expect.any(Number),
262267
})
263268

264269
consoleMock.mockRestore()
@@ -703,11 +708,11 @@ describe('useQuery', () => {
703708

704709
expect(states.length).toBe(4)
705710
// Initial
706-
expect(states[0]).toMatchObject({ data: undefined, updatedAt: 0 })
711+
expect(states[0]).toMatchObject({ data: undefined, dataUpdatedAt: 0 })
707712
// Fetched
708713
expect(states[1]).toMatchObject({ data: 1 })
709714
// Switch
710-
expect(states[2]).toMatchObject({ data: undefined, updatedAt: 0 })
715+
expect(states[2]).toMatchObject({ data: undefined, dataUpdatedAt: 0 })
711716
// Fetched
712717
expect(states[3]).toMatchObject({ data: 2 })
713718
})

0 commit comments

Comments
 (0)