Skip to content

Commit

Permalink
feat: determine staleness locally instead of globally
Browse files Browse the repository at this point in the history
  • Loading branch information
boschni committed Aug 28, 2020
1 parent 8f6bdf3 commit 355e866
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 136 deletions.
91 changes: 18 additions & 73 deletions src/core/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export interface QueryState<TResult, TError> {
isFetchingMore: IsFetchingMoreValue
isIdle: boolean
isLoading: boolean
isStale: boolean
isSuccess: boolean
status: QueryStatus
throwInErrorBoundary?: boolean
Expand All @@ -66,7 +65,6 @@ export interface RefetchOptions {

export enum ActionType {
Failed = 'Failed',
MarkStale = 'MarkStale',
Fetch = 'Fetch',
Success = 'Success',
Error = 'Error',
Expand All @@ -76,10 +74,6 @@ interface FailedAction {
type: ActionType.Failed
}

interface MarkStaleAction {
type: ActionType.MarkStale
}

interface FetchAction {
type: ActionType.Fetch
isFetchingMore?: IsFetchingMoreValue
Expand All @@ -89,7 +83,6 @@ interface SuccessAction<TResult> {
type: ActionType.Success
data: TResult | undefined
canFetchMore?: boolean
isStale: boolean
}

interface ErrorAction<TError> {
Expand All @@ -101,7 +94,6 @@ export type Action<TResult, TError> =
| ErrorAction<TError>
| FailedAction
| FetchAction
| MarkStaleAction
| SuccessAction<TResult>

// CLASS
Expand Down Expand Up @@ -136,7 +128,6 @@ export class Query<TResult, TError> {

activateTimeouts(): void {
this.enableTimeouts = true
this.rescheduleStaleTimeout()
this.rescheduleGarbageCollection()
}

Expand All @@ -150,45 +141,6 @@ export class Query<TResult, TError> {
this.notifyGlobalListeners(this)
}

private rescheduleStaleTimeout(): void {
if (isServer) {
return
}

this.clearStaleTimeout()

if (
!this.enableTimeouts ||
this.state.isStale ||
this.state.status !== QueryStatus.Success ||
this.config.staleTime === Infinity
) {
return
}

const staleTime = this.config.staleTime || 0
let timeout = staleTime
if (this.state.updatedAt) {
const timeElapsed = Date.now() - this.state.updatedAt
const timeUntilStale = staleTime - timeElapsed
timeout = Math.max(timeUntilStale, 0)
}

this.staleTimeout = setTimeout(() => {
this.invalidate()
}, timeout)
}

invalidate(): void {
this.clearStaleTimeout()

if (this.state.isStale) {
return
}

this.dispatch({ type: ActionType.MarkStale })
}

private rescheduleGarbageCollection(): void {
if (isServer) {
return
Expand Down Expand Up @@ -230,7 +182,7 @@ export class Query<TResult, TError> {

private clearTimersObservers(): void {
this.observers.forEach(observer => {
observer.clearRefetchInterval()
observer.clearTimers()
})
}

Expand Down Expand Up @@ -264,20 +216,15 @@ export class Query<TResult, TError> {
data = prevData
}

const isStale = this.config.staleTime === 0

// Try to determine if more data can be fetched
const canFetchMore = hasMorePages(this.config, data)

// Set data and mark it as cached
this.dispatch({
type: ActionType.Success,
data,
isStale,
canFetchMore,
})

this.rescheduleStaleTimeout()
}

clear(): void {
Expand All @@ -293,12 +240,23 @@ export class Query<TResult, TError> {
return this.observers.some(observer => observer.config.enabled)
}

isStale(): boolean {
return this.observers.some(observer => observer.isStale())
}

isStaleByTime(staleTime = 0): boolean {
return (
!this.state.isSuccess || this.state.updatedAt + staleTime <= Date.now()
)
}

onWindowFocus(): void {
if (
this.state.isStale &&
this.observers.some(
observer =>
observer.config.enabled && observer.config.refetchOnWindowFocus
observer.isStale() &&
observer.config.enabled &&
observer.config.refetchOnWindowFocus
)
) {
this.fetch()
Expand All @@ -308,10 +266,11 @@ export class Query<TResult, TError> {

onOnline(): void {
if (
this.state.isStale &&
this.observers.some(
observer =>
observer.config.enabled && observer.config.refetchOnReconnect
observer.isStale() &&
observer.config.enabled &&
observer.config.refetchOnReconnect
)
) {
this.fetch()
Expand Down Expand Up @@ -628,12 +587,6 @@ function getDefaultState<TResult, TError>(

const hasInitialData = typeof initialData !== 'undefined'

const isStale =
!config.enabled ||
(typeof config.initialStale === 'function'
? config.initialStale()
: config.initialStale ?? !hasInitialData)

const initialStatus = hasInitialData
? QueryStatus.Success
: config.enabled
Expand All @@ -647,9 +600,8 @@ function getDefaultState<TResult, TError>(
isFetching: initialStatus === QueryStatus.Loading,
isFetchingMore: false,
failureCount: 0,
isStale,
data: initialData,
updatedAt: hasInitialData ? Date.now() : 0,
updatedAt: Date.now(),
canFetchMore: hasMorePages(config, initialData),
}
}
Expand All @@ -664,11 +616,6 @@ export function queryReducer<TResult, TError>(
...state,
failureCount: state.failureCount + 1,
}
case ActionType.MarkStale:
return {
...state,
isStale: true,
}
case ActionType.Fetch:
const status =
typeof state.data !== 'undefined'
Expand All @@ -687,7 +634,6 @@ export function queryReducer<TResult, TError>(
...getStatusProps(QueryStatus.Success),
data: action.data,
error: null,
isStale: action.isStale,
isFetched: true,
isFetching: false,
isFetchingMore: false,
Expand All @@ -703,7 +649,6 @@ export function queryReducer<TResult, TError>(
isFetched: true,
isFetching: false,
isFetchingMore: false,
isStale: true,
failureCount: state.failureCount + 1,
throwInErrorBoundary: true,
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/queryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export class QueryCache {
}
}

return query.invalidate()
return undefined
})
)
} catch (err) {
Expand Down Expand Up @@ -305,7 +305,7 @@ export class QueryCache {
let query
try {
query = this.buildQuery<TResult, TError>(queryKey, configWithoutRetry)
if (options?.force || query.state.isStale) {
if (options?.force || query.isStaleByTime(config.staleTime)) {
await query.fetch()
}
return query.state.data
Expand Down
Loading

0 comments on commit 355e866

Please sign in to comment.