From d7048d1c35efae5826988448055033fbc59d4c56 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Thu, 25 Jun 2020 10:38:50 -0600 Subject: [PATCH] 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, }) } ``` --- README.md | 27 ++++++++++++++++++++++++--- src/config.js | 1 + src/queryCache.js | 9 +++++++-- types/index.d.ts | 1 + 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3f7cbe5330..e3aaee510c 100644 --- a/README.md +++ b/README.md @@ -920,9 +920,9 @@ There may be times when you already have the initial data for a query synchronou When providing an `initialData` value that is anything other than `undefined`: -- The query `status` will initialize as `success` instead of `loading` -- The query's `isStale` property will initialize as `false` instead of `true` -- The query will not automatically fetch until it is invalidated somehow (eg. window refocus, queryCache refetching, etc) +- The query `status` will initialize in a `success` state instead of `loading` +- The query's `isStale` property will initialize as `false` instead of `true`. This can be overridden by setting the `initialStale` option to `true` +- The query will not automatically fetch until it is invalidated somehow (eg. window refocus, queryCache refetching, `initialStale` is set to `true`, etc) ```js function Todos() { @@ -982,6 +982,23 @@ function Todo({ todoId }) { } ``` +## Marking Initial Data as stale + +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, + }) +} +``` + +> NOTE: Similar to `initialData`, `initialStale` can also be a function for costly calculations, eg. `initialStale: () => isPreview(todoListPreview)`, + ## SSR & Initial Data When using SSR (server-side-rendering) with React Query there are a few things to note: @@ -1795,6 +1812,10 @@ const queryInfo = useQuery({ - Optional - 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) - 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 +- `initialStale: Boolean | Function() => Boolean` + - Optional + - If set, this will mark the `initialData` any `initialData` provided as stale and will likely cause it to be refetched on mount + - 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. - `refetchOnMount: Boolean` - Optional - Defaults to `true` diff --git a/src/config.js b/src/config.js index 16a310282f..16ac6de1e7 100644 --- a/src/config.js +++ b/src/config.js @@ -10,6 +10,7 @@ const DEFAULT_CONFIG = { queries: { queryKeySerializerFn: defaultQueryKeySerializerFn, queryFn: undefined, + initialStale: undefined, enabled: true, retry: 3, retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000), diff --git a/src/queryCache.js b/src/queryCache.js index b7c2b449e9..9b8c70cdab 100644 --- a/src/queryCache.js +++ b/src/queryCache.js @@ -228,7 +228,8 @@ export function makeQueryCache({ frozen = isServer, defaultConfig } = {}) { queryCache.prefetchQuery = async (...args) => { if ( isObject(args[1]) && - (args[1].hasOwnProperty('throwOnError') || args[1].hasOwnProperty('force')) + (args[1].hasOwnProperty('throwOnError') || + args[1].hasOwnProperty('force')) ) { args[3] = args[1] args[1] = undefined @@ -268,7 +269,11 @@ export function makeQueryCache({ frozen = isServer, defaultConfig } = {}) { const hasInitialData = typeof initialData !== 'undefined' - const isStale = !config.enabled || !hasInitialData + const isStale = + !config.enabled || + (typeof config.initialStale === 'function' + ? config.initialStale() + : config.initialStale ?? !hasInitialData) const initialStatus = hasInitialData ? statusSuccess diff --git a/types/index.d.ts b/types/index.d.ts index 0f12c9ccde..2c762fbcd0 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -341,6 +341,7 @@ export interface QueryOptions onSuccess?: (data: TResult) => void onSettled?: (data: TResult | undefined, error: TError | null) => void initialData?: TResult | (() => TResult | undefined) + initialStale?: boolean | (() => boolean | undefined) } export interface PrefetchQueryOptions