Skip to content

Commit 9cb5922

Browse files
perf(vue-query): add shallow flag to improve perf on large datasets (#7733)
* fix(vue-query): use shallowReactive and shallowReadonly to prevent perforamcne slowdown for large datasets * Use shallowReadonly and shallowRef in useMutationState too * fix(vue-query): add shallow option, strip readonly in prod mode --------- Co-authored-by: Damian Osipiuk <[email protected]>
1 parent 0f86b4d commit 9cb5922

File tree

7 files changed

+79
-43
lines changed

7 files changed

+79
-43
lines changed

packages/vue-query/src/useBaseQuery.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import {
22
computed,
33
getCurrentScope,
44
onScopeDispose,
5-
reactive,
65
readonly,
6+
shallowReactive,
7+
shallowReadonly,
78
toRefs,
89
watch,
910
} from 'vue-demi'
@@ -105,7 +106,7 @@ export function useBaseQuery<
105106
})
106107

107108
const observer = new Observer(client, defaultedOptions.value)
108-
const state = reactive(observer.getCurrentResult())
109+
const state = shallowReactive(observer.getCurrentResult())
109110

110111
let unsubscribe = () => {
111112
// noop
@@ -201,7 +202,15 @@ export function useBaseQuery<
201202
},
202203
)
203204

204-
const object: any = toRefs(readonly(state))
205+
const readonlyState =
206+
process.env.NODE_ENV === 'production'
207+
? state
208+
: // @ts-expect-error
209+
defaultedOptions.value.shallow
210+
? shallowReadonly(state)
211+
: readonly(state)
212+
213+
const object: any = toRefs(readonlyState)
205214
for (const key in state) {
206215
if (typeof state[key as keyof typeof state] === 'function') {
207216
object[key] = state[key as keyof typeof state]

packages/vue-query/src/useInfiniteQuery.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ export type UseInfiniteQueryOptions<
4949
TPageParam
5050
>[Property]
5151
>
52+
} & {
53+
shallow?: boolean
5254
}
5355

5456
export type UseInfiniteQueryReturnType<TData, TError> = UseBaseQueryReturnType<

packages/vue-query/src/useMutation.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import {
22
computed,
33
getCurrentScope,
44
onScopeDispose,
5-
reactive,
65
readonly,
6+
shallowReactive,
7+
shallowReadonly,
78
toRefs,
89
watch,
910
} from 'vue-demi'
@@ -26,12 +27,17 @@ type MutationResult<TData, TError, TVariables, TContext> = DistributiveOmit<
2627
'mutate' | 'reset'
2728
>
2829

30+
type UseMutationOptionsBase<TData, TError, TVariables, TContext> =
31+
MutationObserverOptions<TData, TError, TVariables, TContext> & {
32+
shallow?: boolean
33+
}
34+
2935
export type UseMutationOptions<
3036
TData = unknown,
3137
TError = DefaultError,
3238
TVariables = void,
3339
TContext = unknown,
34-
> = MaybeRefDeep<MutationObserverOptions<TData, TError, TVariables, TContext>>
40+
> = MaybeRefDeep<UseMutationOptionsBase<TData, TError, TVariables, TContext>>
3541

3642
type MutateSyncFunction<
3743
TData = unknown,
@@ -61,7 +67,7 @@ export function useMutation<
6167
TContext = unknown,
6268
>(
6369
mutationOptions: MaybeRefDeep<
64-
MutationObserverOptions<TData, TError, TVariables, TContext>
70+
UseMutationOptionsBase<TData, TError, TVariables, TContext>
6571
>,
6672
queryClient?: QueryClient,
6773
): UseMutationReturnType<TData, TError, TVariables, TContext> {
@@ -78,7 +84,7 @@ export function useMutation<
7884
return client.defaultMutationOptions(cloneDeepUnref(mutationOptions))
7985
})
8086
const observer = new MutationObserver(client, options.value)
81-
const state = reactive(observer.getCurrentResult())
87+
const state = shallowReactive(observer.getCurrentResult())
8288

8389
const unsubscribe = observer.subscribe((result) => {
8490
updateState(state, result)
@@ -101,7 +107,14 @@ export function useMutation<
101107
unsubscribe()
102108
})
103109

104-
const resultRefs = toRefs(readonly(state)) as unknown as ToRefs<
110+
const readonlyState =
111+
process.env.NODE_ENV === 'production'
112+
? state
113+
: options.value.shallow
114+
? shallowReadonly(state)
115+
: readonly(state)
116+
117+
const resultRefs = toRefs(readonlyState) as ToRefs<
105118
Readonly<MutationResult<TData, TError, TVariables, TContext>>
106119
>
107120

packages/vue-query/src/useMutationState.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import {
22
computed,
33
getCurrentScope,
44
onScopeDispose,
5-
readonly,
6-
ref,
5+
shallowReadonly,
6+
shallowRef,
77
watch,
88
} from 'vue-demi'
99
import { useQueryClient } from './useQueryClient'
1010
import { cloneDeepUnref } from './utils'
11-
import type { DeepReadonly, Ref } from 'vue-demi'
11+
import type { Ref } from 'vue-demi'
1212
import type {
1313
MutationFilters as MF,
1414
Mutation,
@@ -68,10 +68,12 @@ function getResult<TResult = MutationState>(
6868
export function useMutationState<TResult = MutationState>(
6969
options: MutationStateOptions<TResult> = {},
7070
queryClient?: QueryClient,
71-
): DeepReadonly<Ref<Array<TResult>>> {
71+
): Readonly<Ref<Array<TResult>>> {
7272
const filters = computed(() => cloneDeepUnref(options.filters))
7373
const mutationCache = (queryClient || useQueryClient()).getMutationCache()
74-
const state = ref(getResult(mutationCache, options)) as Ref<Array<TResult>>
74+
const state = shallowRef(getResult(mutationCache, options)) as Ref<
75+
Array<TResult>
76+
>
7577
const unsubscribe = mutationCache.subscribe(() => {
7678
const result = getResult(mutationCache, options)
7779
state.value = result
@@ -85,5 +87,5 @@ export function useMutationState<TResult = MutationState>(
8587
unsubscribe()
8688
})
8789

88-
return readonly(state)
90+
return shallowReadonly(state)
8991
}

packages/vue-query/src/useQueries.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
getCurrentScope,
55
onScopeDispose,
66
readonly,
7+
shallowReadonly,
78
shallowRef,
89
unref,
910
watch,
@@ -256,6 +257,7 @@ export function useQueries<
256257
}: {
257258
queries: MaybeRefDeep<UseQueriesOptionsArg<T>>
258259
combine?: (result: UseQueriesResults<T>) => TCombinedResult
260+
shallow?: boolean
259261
},
260262
queryClient?: QueryClient,
261263
): Readonly<Ref<TCombinedResult>> {
@@ -348,5 +350,9 @@ export function useQueries<
348350
unsubscribe()
349351
})
350352

351-
return readonly(state) as Readonly<Ref<TCombinedResult>>
353+
return process.env.NODE_ENV === 'production'
354+
? state
355+
: options.shallow
356+
? shallowReadonly(state)
357+
: (readonly(state) as Readonly<Ref<TCombinedResult>>)
352358
}

packages/vue-query/src/useQuery.ts

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,37 @@ export type UseQueryOptions<
2323
TData = TQueryFnData,
2424
TQueryData = TQueryFnData,
2525
TQueryKey extends QueryKey = QueryKey,
26-
> = MaybeRef<{
27-
[Property in keyof QueryObserverOptions<
28-
TQueryFnData,
29-
TError,
30-
TData,
31-
TQueryData,
32-
TQueryKey
33-
>]: Property extends 'enabled'
34-
? MaybeRefOrGetter<
35-
QueryObserverOptions<
36-
TQueryFnData,
37-
TError,
38-
TData,
39-
TQueryData,
40-
DeepUnwrapRef<TQueryKey>
41-
>[Property]
42-
>
43-
: MaybeRefDeep<
44-
QueryObserverOptions<
45-
TQueryFnData,
46-
TError,
47-
TData,
48-
TQueryData,
49-
DeepUnwrapRef<TQueryKey>
50-
>[Property]
51-
>
52-
}>
26+
> = MaybeRef<
27+
{
28+
[Property in keyof QueryObserverOptions<
29+
TQueryFnData,
30+
TError,
31+
TData,
32+
TQueryData,
33+
TQueryKey
34+
>]: Property extends 'enabled'
35+
? MaybeRefOrGetter<
36+
QueryObserverOptions<
37+
TQueryFnData,
38+
TError,
39+
TData,
40+
TQueryData,
41+
DeepUnwrapRef<TQueryKey>
42+
>[Property]
43+
>
44+
: MaybeRefDeep<
45+
QueryObserverOptions<
46+
TQueryFnData,
47+
TError,
48+
TData,
49+
TQueryData,
50+
DeepUnwrapRef<TQueryKey>
51+
>[Property]
52+
>
53+
} & {
54+
shallow?: boolean
55+
}
56+
>
5357

5458
export type UndefinedInitialQueryOptions<
5559
TQueryFnData = unknown,

packages/vue-query/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function getClientKey(key?: string) {
99
}
1010

1111
export function updateState(
12-
state: Record<string, unknown>,
12+
state: Record<string, any>,
1313
update: Record<string, any>,
1414
): void {
1515
Object.keys(state).forEach((key) => {

0 commit comments

Comments
 (0)