Skip to content

Commit 643ac4a

Browse files
committed
refactor: cleanup to reduce file size and add tests
1 parent 1117a51 commit 643ac4a

20 files changed

+275
-151
lines changed

.babelrc

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,15 @@
1111
"@babel/preset-typescript",
1212
"@babel/react"
1313
],
14-
"plugins": ["babel-plugin-transform-async-to-promises"],
14+
"plugins": [
15+
[
16+
"const-enum",
17+
{
18+
"transform": "constObject"
19+
}
20+
],
21+
"babel-plugin-transform-async-to-promises"
22+
],
1523
"env": {
1624
"test": {
1725
"presets": [
@@ -24,7 +32,15 @@
2432
}
2533
]
2634
],
27-
"plugins": ["babel-plugin-transform-async-to-promises"]
35+
"plugins": [
36+
[
37+
"const-enum",
38+
{
39+
"transform": "constObject"
40+
}
41+
],
42+
"babel-plugin-transform-async-to-promises"
43+
]
2844
}
2945
}
3046
}

.eslintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
{
2626
"ignoreParameters": true
2727
}
28-
]
28+
],
29+
"no-shadow": "error"
2930
}
3031
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"@typescript-eslint/parser": "^3.6.1",
6464
"babel-eslint": "^10.1.0",
6565
"babel-jest": "^26.0.1",
66+
"babel-plugin-const-enum": "^1.0.1",
6667
"babel-plugin-transform-async-to-promises": "^0.8.15",
6768
"cross-env": "^7.0.2",
6869
"eslint": "7.x",

src/core/query.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
isDocumentVisible,
1010
isOnline,
1111
isServer,
12+
isValidTimeout,
1213
noop,
1314
replaceEqualDeep,
1415
sleep,
@@ -27,7 +28,6 @@ import { QueryObserver, UpdateListener } from './queryObserver'
2728
// TYPES
2829

2930
interface QueryInitConfig<TResult, TError> {
30-
queryCache: QueryCache
3131
queryKey: ArrayQueryKey
3232
queryHash: string
3333
config: QueryConfig<TResult, TError>
@@ -65,11 +65,11 @@ export interface RefetchOptions {
6565
throwOnError?: boolean
6666
}
6767

68-
export enum ActionType {
69-
Failed = 'Failed',
70-
Fetch = 'Fetch',
71-
Success = 'Success',
72-
Error = 'Error',
68+
const enum ActionType {
69+
Failed,
70+
Fetch,
71+
Success,
72+
Error,
7373
}
7474

7575
interface FailedAction {
@@ -118,7 +118,7 @@ export class Query<TResult, TError> {
118118

119119
constructor(init: QueryInitConfig<TResult, TError>) {
120120
this.config = init.config
121-
this.queryCache = init.queryCache
121+
this.queryCache = init.config.queryCache!
122122
this.queryKey = init.queryKey
123123
this.queryHash = init.queryHash
124124
this.notifyGlobalListeners = init.notifyGlobalListeners
@@ -150,7 +150,7 @@ export class Query<TResult, TError> {
150150

151151
this.clearGcTimeout()
152152

153-
if (this.cacheTime === Infinity || this.observers.length > 0) {
153+
if (this.observers.length > 0 || !isValidTimeout(this.cacheTime)) {
154154
return
155155
}
156156

@@ -234,16 +234,16 @@ export class Query<TResult, TError> {
234234
onInteraction(type: 'focus' | 'online'): void {
235235
// Execute the first observer which is enabled,
236236
// stale and wants to refetch on this interaction.
237-
const observer = this.observers.find(
237+
const staleObserver = this.observers.find(
238238
observer =>
239239
observer.isStale() &&
240240
observer.config.enabled &&
241241
((observer.config.refetchOnWindowFocus && type === 'focus') ||
242242
(observer.config.refetchOnReconnect && type === 'online'))
243243
)
244244

245-
if (observer) {
246-
observer.fetch().catch(noop)
245+
if (staleObserver) {
246+
staleObserver.fetch().catch(noop)
247247
}
248248

249249
// Continue any paused fetch

src/core/queryCache.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,13 @@ export class QueryCache {
8484
this.queries = {}
8585
this.queriesArray = []
8686
this.isFetching = 0
87+
88+
this.notifyGlobalListeners = this.notifyGlobalListeners.bind(this)
8789
}
8890

8991
private notifyGlobalListeners(query?: Query<any, any>) {
9092
this.isFetching = this.getQueries().reduce(
91-
(acc, query) => (query.state.isFetching ? acc + 1 : acc),
93+
(acc, q) => (q.state.isFetching ? acc + 1 : acc),
9294
0
9395
)
9496

@@ -229,13 +231,10 @@ export class QueryCache {
229231
}
230232

231233
const query = new Query<TResult, TError>({
232-
queryCache: this,
233234
queryKey,
234235
queryHash,
235236
config,
236-
notifyGlobalListeners: query => {
237-
this.notifyGlobalListeners(query)
238-
},
237+
notifyGlobalListeners: this.notifyGlobalListeners,
239238
})
240239

241240
if (!this.config.frozen) {
@@ -312,9 +311,11 @@ export class QueryCache {
312311
...config,
313312
})
314313

315-
let query
316314
try {
317-
query = this.buildQuery<TResult, TError>(queryKey, configWithoutRetry)
315+
const query = this.buildQuery<TResult, TError>(
316+
queryKey,
317+
configWithoutRetry
318+
)
318319
if (options?.force || query.isStaleByTime(config.staleTime)) {
319320
await query.fetch(undefined, configWithoutRetry)
320321
}

src/core/queryObserver.ts

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { getStatusProps, isServer, isDocumentVisible } from './utils'
1+
import {
2+
getStatusProps,
3+
isServer,
4+
isDocumentVisible,
5+
isValidTimeout,
6+
} from './utils'
27
import type { QueryResult, QueryObserverConfig } from './types'
38
import type { Query, Action, FetchMoreOptions, RefetchOptions } from './query'
49
import type { QueryCache } from './queryCache'
@@ -90,9 +95,7 @@ export class QueryObserver<TResult, TError> {
9095
// Update refetch interval if needed
9196
if (
9297
config.enabled !== prevConfig.enabled ||
93-
config.refetchInterval !== prevConfig.refetchInterval ||
94-
config.refetchIntervalInBackground !==
95-
prevConfig.refetchIntervalInBackground
98+
config.refetchInterval !== prevConfig.refetchInterval
9699
) {
97100
this.updateRefetchInterval()
98101
}
@@ -163,16 +166,15 @@ export class QueryObserver<TResult, TError> {
163166

164167
this.clearStaleTimeout()
165168

166-
const staleTime = this.config.staleTime || 0
167169
const { isStale, updatedAt } = this.currentResult
168170

169-
if (isStale || staleTime === Infinity) {
171+
if (isStale || !isValidTimeout(this.config.staleTime)) {
170172
return
171173
}
172174

173175
const timeElapsed = Date.now() - updatedAt
174-
const timeUntilStale = staleTime - timeElapsed
175-
const timeout = Math.max(timeUntilStale, 0)
176+
const timeUntilStale = this.config.staleTime - timeElapsed
177+
const timeout = Math.max(timeUntilStale, 1)
176178

177179
this.staleTimeoutId = setTimeout(() => {
178180
this.updateIsStale()
@@ -186,12 +188,7 @@ export class QueryObserver<TResult, TError> {
186188

187189
this.clearRefetchInterval()
188190

189-
if (
190-
!this.config.enabled ||
191-
!this.config.refetchInterval ||
192-
this.config.refetchInterval < 0 ||
193-
this.config.refetchInterval === Infinity
194-
) {
191+
if (!this.config.enabled || !isValidTimeout(this.config.refetchInterval)) {
195192
return
196193
}
197194

@@ -309,6 +306,8 @@ export class QueryObserver<TResult, TError> {
309306
}
310307

311308
onQueryUpdate(action: Action<TResult, TError>): void {
309+
const { type } = action
310+
312311
// Store current result and get new result
313312
const prevResult = this.currentResult
314313
this.updateResult()
@@ -317,11 +316,11 @@ export class QueryObserver<TResult, TError> {
317316

318317
// We need to check the action because the state could have
319318
// transitioned from success to success in case of `setQueryData`.
320-
if (action.type === 'Success' && currentResult.isSuccess) {
319+
if (type === 2) {
321320
config.onSuccess?.(currentResult.data!)
322321
config.onSettled?.(currentResult.data!, null)
323322
this.updateTimers()
324-
} else if (action.type === 'Error' && currentResult.isError) {
323+
} else if (type === 3) {
325324
config.onError?.(currentResult.error!)
326325
config.onSettled?.(undefined, currentResult.error!)
327326
this.updateTimers()

src/core/tests/utils.test.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { deepEqual, replaceEqualDeep } from '../utils'
1+
import { deepEqual, replaceEqualDeep, deepIncludes } from '../utils'
22
import { setConsole, queryCache } from '..'
33
import { queryKey } from '../../react/tests/utils'
44

@@ -29,6 +29,20 @@ describe('core/utils', () => {
2929
setConsole(console)
3030
})
3131

32+
describe('deepIncludes', () => {
33+
it('should return `true` if a includes b', () => {
34+
const a = { a: { b: 'b' }, c: 'c', d: [{ d: 'd ' }] }
35+
const b = { a: { b: 'b' }, c: 'c', d: [] }
36+
expect(deepIncludes(a, b)).toEqual(true)
37+
})
38+
39+
it('should return `false` if a does not include b', () => {
40+
const a = { a: { b: 'b' }, c: 'c', d: [] }
41+
const b = { a: { b: 'b' }, c: 'c', d: [{ d: 'd ' }] }
42+
expect(deepIncludes(a, b)).toEqual(false)
43+
})
44+
})
45+
3246
describe('deepEqual', () => {
3347
it('should return `true` for equal objects', () => {
3448
const a = { a: { b: 'b' }, c: 'c', d: [{ d: 'd ' }] }

src/core/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export function functionalUpdate<TInput, TOutput>(
5454

5555
function stableStringifyReplacer(_key: string, value: any): unknown {
5656
if (typeof value === 'function') {
57-
throw new Error('Cannot stringify non JSON value')
57+
throw new Error()
5858
}
5959

6060
if (isObject(value)) {
@@ -89,6 +89,10 @@ export function deepIncludes(a: any, b: any): boolean {
8989
return false
9090
}
9191

92+
export function isValidTimeout(value: any): value is number {
93+
return typeof value === 'number' && value >= 0 && value !== Infinity
94+
}
95+
9296
export function isDocumentVisible(): boolean {
9397
// document global can be unavailable in react native
9498
if (typeof document === 'undefined') {

src/hydration/tests/hydration.test.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,7 @@ describe('dehydration and rehydration', () => {
134134
// Exact shape is not important here, just that staleTime and cacheTime
135135
// (and any future other config) is not included in it
136136
const dehydratedQuery = dehydrated?.queries.find(
137-
dehydratedQuery =>
138-
(dehydratedQuery?.config?.queryKey as Array<string>)[0] === 'string'
137+
query => (query?.config?.queryKey as Array<string>)[0] === 'string'
139138
)
140139
expect(dehydratedQuery).toBeTruthy()
141140
expect(dehydratedQuery?.config.cacheTime).toBe(undefined)
@@ -180,8 +179,7 @@ describe('dehydration and rehydration', () => {
180179
// This is testing implementation details that can change and are not
181180
// part of the public API, but is important for keeping the payload small
182181
const dehydratedQuery = dehydrated?.queries.find(
183-
dehydratedQuery =>
184-
(dehydratedQuery?.config?.queryKey as Array<string>)[0] === 'string'
182+
query => (query?.config?.queryKey as Array<string>)[0] === 'string'
185183
)
186184
expect(dehydratedQuery).toBeUndefined()
187185

src/react/ReactQueryCacheProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
} from '../core'
88
import { QueryCache } from '../core/queryCache'
99

10-
export const queryCacheContext = React.createContext(defaultQueryCache)
10+
const queryCacheContext = React.createContext(defaultQueryCache)
1111

1212
export const useQueryCache = () => React.useContext(queryCacheContext)
1313

0 commit comments

Comments
 (0)