Skip to content

Commit 00d0c52

Browse files
authored
refactor: inline / remove some functions for size improvements (#3289)
* refactor: size inline reducers in query and mutation because they are only used from dispatch * refactor: remove default case in reducers actions are only produced by our own code, which is in TypeScript, so we'll get a type error if there is an action not handled. Unknown actions can't exist, as the tests show: we'd need a ts-expects-error to go this way * refactor: inline executeMutation because it's only used once * refactor: inline getObserver and updateObservers in useQueries because it's only used once * refactor: extract getDefaultState getDefaultState is a pure function, with no access to `this`, so we can extract it. This is in-line with what `mutation` is doing * refactor: remove getNextResult it was only used in tests, and it's also not documented * refactor: inline clearTimers because it's only used once * refactor: inline shouldNotifyListeners because it's only used once * refactor: inline resumePausedMutations * refactor: tests every stubbed queryFn needs a mock implementation to avoid console errors: Error: Query data cannot be undefined
1 parent 7064c69 commit 00d0c52

13 files changed

+301
-421
lines changed

src/core/mutation.ts

Lines changed: 80 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,33 @@ export class Mutation<
186186
})
187187
}
188188

189+
const executeMutation = () => {
190+
this.retryer = createRetryer({
191+
fn: () => {
192+
if (!this.options.mutationFn) {
193+
return Promise.reject('No mutationFn found')
194+
}
195+
return this.options.mutationFn(this.state.variables!)
196+
},
197+
onFail: () => {
198+
this.dispatch({ type: 'failed' })
199+
},
200+
onPause: () => {
201+
this.dispatch({ type: 'pause' })
202+
},
203+
onContinue: () => {
204+
this.dispatch({ type: 'continue' })
205+
},
206+
retry: this.options.retry ?? 0,
207+
retryDelay: this.options.retryDelay,
208+
networkMode: this.options.networkMode,
209+
})
210+
211+
return this.retryer.promise
212+
}
213+
189214
return promise
190-
.then(() => this.executeMutation())
215+
.then(executeMutation)
191216
.then(result => {
192217
data = result
193218
// Notify cache callback
@@ -253,33 +278,61 @@ export class Mutation<
253278
})
254279
}
255280

256-
private executeMutation(): Promise<TData> {
257-
this.retryer = createRetryer({
258-
fn: () => {
259-
if (!this.options.mutationFn) {
260-
return Promise.reject('No mutationFn found')
261-
}
262-
return this.options.mutationFn(this.state.variables!)
263-
},
264-
onFail: () => {
265-
this.dispatch({ type: 'failed' })
266-
},
267-
onPause: () => {
268-
this.dispatch({ type: 'pause' })
269-
},
270-
onContinue: () => {
271-
this.dispatch({ type: 'continue' })
272-
},
273-
retry: this.options.retry ?? 0,
274-
retryDelay: this.options.retryDelay,
275-
networkMode: this.options.networkMode,
276-
})
277-
278-
return this.retryer.promise
279-
}
280-
281281
private dispatch(action: Action<TData, TError, TVariables, TContext>): void {
282-
this.state = this.reducer(action)
282+
const reducer = (
283+
state: MutationState<TData, TError, TVariables, TContext>
284+
): MutationState<TData, TError, TVariables, TContext> => {
285+
switch (action.type) {
286+
case 'failed':
287+
return {
288+
...state,
289+
failureCount: state.failureCount + 1,
290+
}
291+
case 'pause':
292+
return {
293+
...state,
294+
isPaused: true,
295+
}
296+
case 'continue':
297+
return {
298+
...state,
299+
isPaused: false,
300+
}
301+
case 'loading':
302+
return {
303+
...state,
304+
context: action.context,
305+
data: undefined,
306+
error: null,
307+
isPaused: !canFetch(this.options.networkMode),
308+
status: 'loading',
309+
variables: action.variables,
310+
}
311+
case 'success':
312+
return {
313+
...state,
314+
data: action.data,
315+
error: null,
316+
status: 'success',
317+
isPaused: false,
318+
}
319+
case 'error':
320+
return {
321+
...state,
322+
data: undefined,
323+
error: action.error,
324+
failureCount: state.failureCount + 1,
325+
isPaused: false,
326+
status: 'error',
327+
}
328+
case 'setState':
329+
return {
330+
...state,
331+
...action.state,
332+
}
333+
}
334+
}
335+
this.state = reducer(this.state)
283336

284337
notifyManager.batch(() => {
285338
this.observers.forEach(observer => {
@@ -292,62 +345,6 @@ export class Mutation<
292345
})
293346
})
294347
}
295-
296-
private reducer(
297-
action: Action<TData, TError, TVariables, TContext>
298-
): MutationState<TData, TError, TVariables, TContext> {
299-
switch (action.type) {
300-
case 'failed':
301-
return {
302-
...this.state,
303-
failureCount: this.state.failureCount + 1,
304-
}
305-
case 'pause':
306-
return {
307-
...this.state,
308-
isPaused: true,
309-
}
310-
case 'continue':
311-
return {
312-
...this.state,
313-
isPaused: false,
314-
}
315-
case 'loading':
316-
return {
317-
...this.state,
318-
context: action.context,
319-
data: undefined,
320-
error: null,
321-
isPaused: !canFetch(this.options.networkMode),
322-
status: 'loading',
323-
variables: action.variables,
324-
}
325-
case 'success':
326-
return {
327-
...this.state,
328-
data: action.data,
329-
error: null,
330-
status: 'success',
331-
isPaused: false,
332-
}
333-
case 'error':
334-
return {
335-
...this.state,
336-
data: undefined,
337-
error: action.error,
338-
failureCount: this.state.failureCount + 1,
339-
isPaused: false,
340-
status: 'error',
341-
}
342-
case 'setState':
343-
return {
344-
...this.state,
345-
...action.state,
346-
}
347-
default:
348-
return this.state
349-
}
350-
}
351348
}
352349

353350
export function getDefaultState<

src/core/mutationCache.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,6 @@ export class MutationCache extends Subscribable<MutationCacheListener> {
143143
})
144144
}
145145

146-
onFocus(): void {
147-
this.resumePausedMutations()
148-
}
149-
150-
onOnline(): void {
151-
this.resumePausedMutations()
152-
}
153-
154146
resumePausedMutations(): Promise<void> {
155147
const pausedMutations = this.mutations.filter(x => x.state.isPaused)
156148
return notifyManager.batch(() =>

src/core/queriesObserver.ts

Lines changed: 53 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,52 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
6060
notifyOptions?: NotifyOptions
6161
): void {
6262
this.queries = queries
63-
this.updateObservers(notifyOptions)
63+
64+
notifyManager.batch(() => {
65+
const prevObservers = this.observers
66+
67+
const newObserverMatches = this.findMatchingObservers(this.queries)
68+
69+
// set options for the new observers to notify of changes
70+
newObserverMatches.forEach(match =>
71+
match.observer.setOptions(match.defaultedQueryOptions, notifyOptions)
72+
)
73+
74+
const newObservers = newObserverMatches.map(match => match.observer)
75+
const newObserversMap = Object.fromEntries(
76+
newObservers.map(observer => [observer.options.queryHash, observer])
77+
)
78+
const newResult = newObservers.map(observer =>
79+
observer.getCurrentResult()
80+
)
81+
82+
const hasIndexChange = newObservers.some(
83+
(observer, index) => observer !== prevObservers[index]
84+
)
85+
if (prevObservers.length === newObservers.length && !hasIndexChange) {
86+
return
87+
}
88+
89+
this.observers = newObservers
90+
this.observersMap = newObserversMap
91+
this.result = newResult
92+
93+
if (!this.hasListeners()) {
94+
return
95+
}
96+
97+
difference(prevObservers, newObservers).forEach(observer => {
98+
observer.destroy()
99+
})
100+
101+
difference(newObservers, prevObservers).forEach(observer => {
102+
observer.subscribe(result => {
103+
this.onUpdate(observer, result)
104+
})
105+
})
106+
107+
this.notify()
108+
})
64109
}
65110

66111
getCurrentResult(): QueryObserverResult[] {
@@ -106,6 +151,12 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
106151
!matchingObservers.some(match => match.observer === prevObserver)
107152
)
108153

154+
const getObserver = (options: QueryObserverOptions): QueryObserver => {
155+
const defaultedOptions = this.client.defaultQueryOptions(options)
156+
const currentObserver = this.observersMap[defaultedOptions.queryHash!]
157+
return currentObserver ?? new QueryObserver(this.client, defaultedOptions)
158+
}
159+
109160
const newOrReusedObservers: QueryObserverMatch[] = unmatchedQueries.map(
110161
(options, index) => {
111162
if (options.keepPreviousData) {
@@ -120,7 +171,7 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
120171
}
121172
return {
122173
defaultedQueryOptions: options,
123-
observer: this.getObserver(options),
174+
observer: getObserver(options),
124175
}
125176
}
126177
)
@@ -137,60 +188,6 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
137188
.sort(sortMatchesByOrderOfQueries)
138189
}
139190

140-
private getObserver(options: QueryObserverOptions): QueryObserver {
141-
const defaultedOptions = this.client.defaultQueryOptions(options)
142-
const currentObserver = this.observersMap[defaultedOptions.queryHash!]
143-
return currentObserver ?? new QueryObserver(this.client, defaultedOptions)
144-
}
145-
146-
private updateObservers(notifyOptions?: NotifyOptions): void {
147-
notifyManager.batch(() => {
148-
const prevObservers = this.observers
149-
150-
const newObserverMatches = this.findMatchingObservers(this.queries)
151-
152-
// set options for the new observers to notify of changes
153-
newObserverMatches.forEach(match =>
154-
match.observer.setOptions(match.defaultedQueryOptions, notifyOptions)
155-
)
156-
157-
const newObservers = newObserverMatches.map(match => match.observer)
158-
const newObserversMap = Object.fromEntries(
159-
newObservers.map(observer => [observer.options.queryHash, observer])
160-
)
161-
const newResult = newObservers.map(observer =>
162-
observer.getCurrentResult()
163-
)
164-
165-
const hasIndexChange = newObservers.some(
166-
(observer, index) => observer !== prevObservers[index]
167-
)
168-
if (prevObservers.length === newObservers.length && !hasIndexChange) {
169-
return
170-
}
171-
172-
this.observers = newObservers
173-
this.observersMap = newObserversMap
174-
this.result = newResult
175-
176-
if (!this.hasListeners()) {
177-
return
178-
}
179-
180-
difference(prevObservers, newObservers).forEach(observer => {
181-
observer.destroy()
182-
})
183-
184-
difference(newObservers, prevObservers).forEach(observer => {
185-
observer.subscribe(result => {
186-
this.onUpdate(observer, result)
187-
})
188-
})
189-
190-
this.notify()
191-
})
192-
}
193-
194191
private onUpdate(observer: QueryObserver, result: QueryObserverResult): void {
195192
const index = this.observers.indexOf(observer)
196193
if (index !== -1) {

0 commit comments

Comments
 (0)