Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions docs/src/pages/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ const {
error,
failureCount,
isError,
isFetchedAfterMount,
isFetching,
isIdle,
isLoading,
isPreviousData,
isStale,
isSuccess,
refetch,
Expand Down Expand Up @@ -100,8 +102,7 @@ const queryInfo = useQuery({
- Set this to `true` or `false` to enable/disable automatic refetching on reconnect for this query.
- `notifyOnStatusChange: Boolean`
- Optional
- Whether a change to the query status should re-render a component.
- If set to `false`, the component will only re-render when the actual `data` or `error` changes.
- Set this to `false` to only re-render when there are changes to `data` or `error`.
- Defaults to `true`.
- `onSuccess: Function(data) => data`
- Optional
Expand Down Expand Up @@ -170,6 +171,11 @@ const queryInfo = useQuery({
- The error object for the query, if an error was thrown.
- `isStale: Boolean`
- Will be `true` if the cache data is stale.
- `isPreviousData: Boolean`
- Will be `true` when `keepPreviousData` is set and data from the previous query is returned.
- `isFetchedAfterMount: Boolean`
- Will be `true` if the query has been fetched after the component mounted.
- This property can be used to not show any previously cached data.
- `isFetching: Boolean`
- Defaults to `true` so long as `manual` is set to `false`
- Will be `true` if the query is currently fetching, including background fetching.
Expand Down
12 changes: 6 additions & 6 deletions src/core/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,16 @@ export const DEFAULT_STALE_TIME = 0
export const DEFAULT_CACHE_TIME = 5 * 60 * 1000
export const DEFAULT_CONFIG: ReactQueryConfig = {
queries: {
queryKeySerializerFn: defaultQueryKeySerializerFn,
cacheTime: DEFAULT_CACHE_TIME,
enabled: true,
notifyOnStatusChange: true,
queryKeySerializerFn: defaultQueryKeySerializerFn,
refetchOnMount: true,
refetchOnReconnect: true,
refetchOnWindowFocus: true,
retry: 3,
retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000),
staleTime: DEFAULT_STALE_TIME,
cacheTime: DEFAULT_CACHE_TIME,
refetchOnWindowFocus: true,
refetchOnReconnect: true,
refetchOnMount: true,
notifyOnStatusChange: true,
structuralSharing: true,
},
}
Expand Down
21 changes: 9 additions & 12 deletions src/core/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
isDocumentVisible,
isOnline,
isServer,
noop,
replaceEqualDeep,
sleep,
} from './utils'
Expand Down Expand Up @@ -38,6 +39,7 @@ export interface QueryState<TResult, TError> {
data?: TResult
error: TError | null
failureCount: number
fetchedCount: number
isError: boolean
isFetched: boolean
isFetching: boolean
Expand Down Expand Up @@ -229,7 +231,7 @@ export class Query<TResult, TError> {
)
}

async onWindowFocus(): Promise<void> {
onWindowFocus(): void {
if (
this.observers.some(
observer =>
Expand All @@ -238,17 +240,13 @@ export class Query<TResult, TError> {
observer.config.refetchOnWindowFocus
)
) {
try {
await this.fetch()
} catch {
// ignore
}
this.fetch().catch(noop)
}

this.continue()
}

async onOnline(): Promise<void> {
onOnline(): void {
if (
this.observers.some(
observer =>
Expand All @@ -257,11 +255,7 @@ export class Query<TResult, TError> {
observer.config.refetchOnReconnect
)
) {
try {
await this.fetch()
} catch {
// ignore
}
this.fetch().catch(noop)
}

this.continue()
Expand Down Expand Up @@ -612,6 +606,7 @@ function getDefaultState<TResult, TError>(
isFetching: initialStatus === QueryStatus.Loading,
isFetchingMore: false,
failureCount: 0,
fetchedCount: 0,
data: initialData,
updatedAt: Date.now(),
canFetchMore: hasMorePages(config, initialData),
Expand Down Expand Up @@ -646,6 +641,7 @@ export function queryReducer<TResult, TError>(
...getStatusProps(QueryStatus.Success),
data: action.data,
error: null,
fetchedCount: state.fetchedCount + 1,
isFetched: true,
isFetching: false,
isFetchingMore: false,
Expand All @@ -658,6 +654,7 @@ export function queryReducer<TResult, TError>(
...state,
...getStatusProps(QueryStatus.Error),
error: action.error,
fetchedCount: state.fetchedCount + 1,
isFetched: true,
isFetching: false,
isFetchingMore: false,
Expand Down
14 changes: 12 additions & 2 deletions src/core/queryObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ export class QueryObserver<TResult, TError> {
private currentResult!: QueryResult<TResult, TError>
private previousQueryResult?: QueryResult<TResult, TError>
private updateListener?: UpdateListener<TResult, TError>
private initialFetchedCount: number
private staleTimeoutId?: number
private refetchIntervalId?: number
private started?: boolean

constructor(config: QueryObserverConfig<TResult, TError>) {
this.config = config
this.queryCache = config.queryCache!
this.initialFetchedCount = 0

// Bind exposed methods
this.clear = this.clear.bind(this)
Expand Down Expand Up @@ -100,6 +102,10 @@ export class QueryObserver<TResult, TError> {
return this.currentResult.isStale
}

getCurrentQuery(): Query<TResult, TError> {
return this.currentQuery
}

getCurrentResult(): QueryResult<TResult, TError> {
return this.currentResult
}
Expand Down Expand Up @@ -224,16 +230,18 @@ export class QueryObserver<TResult, TError> {
const { currentQuery, currentResult, previousQueryResult, config } = this
const { state } = currentQuery
let { data, status, updatedAt } = state
let isPreviousData = false

// Keep previous data if needed
if (
config.keepPreviousData &&
state.isLoading &&
(state.isIdle || state.isLoading) &&
previousQueryResult?.isSuccess
) {
data = previousQueryResult.data
updatedAt = previousQueryResult.updatedAt
status = previousQueryResult.status
isPreviousData = true
}

let isStale = false
Expand Down Expand Up @@ -261,10 +269,11 @@ export class QueryObserver<TResult, TError> {
failureCount: state.failureCount,
fetchMore: this.fetchMore,
isFetched: state.isFetched,
isFetchedAfterMount: state.fetchedCount > this.initialFetchedCount,
isFetching: state.isFetching,
isFetchingMore: state.isFetchingMore,
isPreviousData,
isStale,
query: currentQuery,
refetch: this.refetch,
updatedAt,
}
Expand All @@ -288,6 +297,7 @@ export class QueryObserver<TResult, TError> {

this.previousQueryResult = this.currentResult
this.currentQuery = newQuery
this.initialFetchedCount = newQuery.state.fetchedCount
this.updateResult()

if (this.started) {
Expand Down
10 changes: 3 additions & 7 deletions src/core/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Query, FetchMoreOptions, RefetchOptions } from './query'
import type { FetchMoreOptions, RefetchOptions } from './query'
import type { QueryCache } from './queryCache'

export type QueryKey =
Expand Down Expand Up @@ -34,11 +34,6 @@ export type QueryKeySerializerFunction = (
) => [string, QueryKey[]]

export interface BaseQueryConfig<TResult, TError = unknown, TData = TResult> {
/**
* Set this to `false` to disable automatic refetching when the query mounts or changes query keys.
* To refetch the query, use the `refetch` method returned from the `useQuery` instance.
*/
enabled?: boolean | unknown
/**
* If `false`, failed queries will not retry by default.
* If `true`, failed queries will retry infinitely., failureCount: num
Expand Down Expand Up @@ -180,13 +175,14 @@ export interface QueryResultBase<TResult, TError = unknown> {
) => Promise<TResult | undefined>
isError: boolean
isFetched: boolean
isFetchedAfterMount: boolean
isFetching: boolean
isFetchingMore?: IsFetchingMoreValue
isIdle: boolean
isLoading: boolean
isStale: boolean
isSuccess: boolean
query: Query<TResult, TError>
isPreviousData: boolean
refetch: (options?: RefetchOptions) => Promise<TResult | undefined>
status: QueryStatus
updatedAt: number
Expand Down
2 changes: 1 addition & 1 deletion src/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const uid = () => _uid++

export const isServer = typeof window === 'undefined'

function noop(): void {
export function noop(): void {
return void 0
}

Expand Down
12 changes: 10 additions & 2 deletions src/react/tests/useInfiniteQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,14 @@ describe('useInfiniteQuery', () => {
fetchMore: expect.any(Function),
isError: false,
isFetched: false,
isFetchedAfterMount: false,
isFetching: true,
isFetchingMore: false,
isIdle: false,
isLoading: true,
isPreviousData: false,
isStale: true,
isSuccess: false,
query: expect.any(Object),
refetch: expect.any(Function),
status: 'loading',
updatedAt: expect.any(Number),
Expand All @@ -96,12 +97,13 @@ describe('useInfiniteQuery', () => {
isFetchingMore: false,
isError: false,
isFetched: true,
isFetchedAfterMount: true,
isFetching: false,
isIdle: false,
isLoading: false,
isPreviousData: false,
isStale: true,
isSuccess: true,
query: expect.any(Object),
refetch: expect.any(Function),
status: 'success',
updatedAt: expect.any(Number),
Expand Down Expand Up @@ -152,36 +154,42 @@ describe('useInfiniteQuery', () => {
isFetching: true,
isFetchingMore: false,
isSuccess: false,
isPreviousData: false,
})
expect(states[1]).toMatchObject({
data: ['0-desc'],
isFetching: false,
isFetchingMore: false,
isSuccess: true,
isPreviousData: false,
})
expect(states[2]).toMatchObject({
data: ['0-desc'],
isFetching: true,
isFetchingMore: 'next',
isSuccess: true,
isPreviousData: false,
})
expect(states[3]).toMatchObject({
data: ['0-desc', '1-desc'],
isFetching: false,
isFetchingMore: false,
isSuccess: true,
isPreviousData: false,
})
expect(states[4]).toMatchObject({
data: ['0-desc', '1-desc'],
isFetching: true,
isFetchingMore: false,
isSuccess: true,
isPreviousData: true,
})
expect(states[5]).toMatchObject({
data: ['0-asc'],
isFetching: false,
isFetchingMore: false,
isSuccess: true,
isPreviousData: false,
})
})

Expand Down
7 changes: 5 additions & 2 deletions src/react/tests/usePaginatedQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ describe('usePaginatedQuery', () => {
fetchMore: expect.any(Function),
isError: false,
isFetched: false,
isFetchedAfterMount: false,
isFetching: true,
isFetchingMore: false,
isIdle: false,
isLoading: true,
isPreviousData: false,
isStale: true,
isSuccess: false,
query: expect.any(Object),
latestData: undefined,
resolvedData: undefined,
refetch: expect.any(Function),
Expand All @@ -64,13 +65,14 @@ describe('usePaginatedQuery', () => {
fetchMore: expect.any(Function),
isError: false,
isFetched: true,
isFetchedAfterMount: true,
isFetching: false,
isFetchingMore: false,
isIdle: false,
isLoading: false,
isPreviousData: false,
isStale: true,
isSuccess: true,
query: expect.any(Object),
latestData: 1,
resolvedData: 1,
refetch: expect.any(Function),
Expand Down Expand Up @@ -208,6 +210,7 @@ describe('usePaginatedQuery', () => {
},
{
enabled: searchTerm,
keepPreviousData: page !== 1,
}
)

Expand Down
Loading