Skip to content

Commit d7048d1

Browse files
committed
feat: add initialStale option to queries
By default `initialData` is not considered stale, but sometimes you may want it to be, for instance, if your initial data is only a partial subset of an object and you know you will need to refetch the full version immediately after mounting. For this, you can use the `initialStale: true` options. By setting `initialStale` to `true`, the `initialData` will be considered `stale` and will cause a refetch when the query mounts for the first time. ```js function Todos() { const queryInfo = useQuery('todos', () => fetch('/todos'), { initialData: todoListPreview, initialStale: true, }) } ```
1 parent 8ec83f4 commit d7048d1

File tree

4 files changed

+33
-5
lines changed

4 files changed

+33
-5
lines changed

README.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -920,9 +920,9 @@ There may be times when you already have the initial data for a query synchronou
920920

921921
When providing an `initialData` value that is anything other than `undefined`:
922922

923-
- The query `status` will initialize as `success` instead of `loading`
924-
- The query's `isStale` property will initialize as `false` instead of `true`
925-
- The query will not automatically fetch until it is invalidated somehow (eg. window refocus, queryCache refetching, etc)
923+
- The query `status` will initialize in a `success` state instead of `loading`
924+
- The query's `isStale` property will initialize as `false` instead of `true`. This can be overridden by setting the `initialStale` option to `true`
925+
- The query will not automatically fetch until it is invalidated somehow (eg. window refocus, queryCache refetching, `initialStale` is set to `true`, etc)
926926

927927
```js
928928
function Todos() {
@@ -982,6 +982,23 @@ function Todo({ todoId }) {
982982
}
983983
```
984984
985+
## Marking Initial Data as stale
986+
987+
By default `initialData` is not considered stale, but sometimes you may want it to be, for instance, if your initial data is only a partial subset of an object and you know you will need to refetch the full version immediately after mounting. For this, you can use the `initialStale: true` options.
988+
989+
By setting `initialStale` to `true`, the `initialData` will be considered `stale` and will cause a refetch when the query mounts for the first time.
990+
991+
```js
992+
function Todos() {
993+
const queryInfo = useQuery('todos', () => fetch('/todos'), {
994+
initialData: todoListPreview,
995+
initialStale: true,
996+
})
997+
}
998+
```
999+
1000+
> NOTE: Similar to `initialData`, `initialStale` can also be a function for costly calculations, eg. `initialStale: () => isPreview(todoListPreview)`,
1001+
9851002
## SSR & Initial Data
9861003
9871004
When using SSR (server-side-rendering) with React Query there are a few things to note:
@@ -1795,6 +1812,10 @@ const queryInfo = useQuery({
17951812
- Optional
17961813
- If set, this value will be used as the initial data for the query cache (as long as the query hasn't been created or cached yet)
17971814
- If set to a function, the function will be called **once** during the shared/root query initialization, and be expected to synchronously return the initialData
1815+
- `initialStale: Boolean | Function() => Boolean`
1816+
- Optional
1817+
- If set, this will mark the `initialData` any `initialData` provided as stale and will likely cause it to be refetched on mount
1818+
- If a function is passed, it will be called only when appropriate to resolve the `initialStale` value. This can be useful if your `initialStale` value is costly to calculate.
17981819
- `refetchOnMount: Boolean`
17991820
- Optional
18001821
- Defaults to `true`

src/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const DEFAULT_CONFIG = {
1010
queries: {
1111
queryKeySerializerFn: defaultQueryKeySerializerFn,
1212
queryFn: undefined,
13+
initialStale: undefined,
1314
enabled: true,
1415
retry: 3,
1516
retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000),

src/queryCache.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ export function makeQueryCache({ frozen = isServer, defaultConfig } = {}) {
228228
queryCache.prefetchQuery = async (...args) => {
229229
if (
230230
isObject(args[1]) &&
231-
(args[1].hasOwnProperty('throwOnError') || args[1].hasOwnProperty('force'))
231+
(args[1].hasOwnProperty('throwOnError') ||
232+
args[1].hasOwnProperty('force'))
232233
) {
233234
args[3] = args[1]
234235
args[1] = undefined
@@ -268,7 +269,11 @@ export function makeQueryCache({ frozen = isServer, defaultConfig } = {}) {
268269

269270
const hasInitialData = typeof initialData !== 'undefined'
270271

271-
const isStale = !config.enabled || !hasInitialData
272+
const isStale =
273+
!config.enabled ||
274+
(typeof config.initialStale === 'function'
275+
? config.initialStale()
276+
: config.initialStale ?? !hasInitialData)
272277

273278
const initialStatus = hasInitialData
274279
? statusSuccess

types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ export interface QueryOptions<TResult, TError = Error>
341341
onSuccess?: (data: TResult) => void
342342
onSettled?: (data: TResult | undefined, error: TError | null) => void
343343
initialData?: TResult | (() => TResult | undefined)
344+
initialStale?: boolean | (() => boolean | undefined)
344345
}
345346

346347
export interface PrefetchQueryOptions<TResult, TError = Error>

0 commit comments

Comments
 (0)