Skip to content

Commit f7a98b6

Browse files
committed
feat: useIsFetching reactivity improvements
1 parent 7374ed1 commit f7a98b6

File tree

4 files changed

+75
-122
lines changed

4 files changed

+75
-122
lines changed

src/vuejs/__tests__/useIsFetching.test.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { onScopeDispose } from "vue-demi";
1+
import { onScopeDispose, reactive } from "vue-demi";
22

33
import { flushPromises, simpleFetcher } from "./test-utils";
44
import { useQuery } from "../useQuery";
5-
import { useIsFetching } from "../useIsFetching";
5+
import { parseFilterArgs, useIsFetching } from "../useIsFetching";
66

77
jest.mock("../useQueryClient");
88

@@ -28,6 +28,29 @@ describe("useIsFetching", () => {
2828
expect(isFetching.value).toStrictEqual(0);
2929
});
3030

31+
test("should properly update filters", async () => {
32+
const filter = reactive({ stale: false });
33+
useQuery(
34+
["isFetching"],
35+
() =>
36+
new Promise((resolve) => {
37+
setTimeout(() => {
38+
return resolve("Some data");
39+
}, 100);
40+
})
41+
);
42+
const isFetching = useIsFetching(filter);
43+
44+
expect(isFetching.value).toStrictEqual(0);
45+
46+
filter.stale = true;
47+
await flushPromises();
48+
49+
expect(isFetching.value).toStrictEqual(1);
50+
51+
await flushPromises(100);
52+
});
53+
3154
test("should stop listening to changes on onScopeDispose", async () => {
3255
const onScopeDisposeMock = onScopeDispose as jest.MockedFunction<
3356
typeof onScopeDispose
@@ -52,4 +75,21 @@ describe("useIsFetching", () => {
5275

5376
onScopeDisposeMock.mockReset();
5477
});
78+
79+
describe("parseFilterArgs", () => {
80+
test("should default to empty filters", () => {
81+
const result = parseFilterArgs(undefined);
82+
83+
expect(result).toEqual({});
84+
});
85+
86+
test("should merge query key with filters", () => {
87+
const filters = { stale: true };
88+
89+
const result = parseFilterArgs(["key"], filters);
90+
const expected = { ...filters, queryKey: ["key"] };
91+
92+
expect(result).toEqual(expected);
93+
});
94+
});
5595
});

src/vuejs/__tests__/utils.test.ts

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import { successMutator, simpleFetcher } from "./test-utils";
1+
import { successMutator } from "./test-utils";
22
import {
33
isQueryKey,
4-
parseFilterArgs,
54
parseMutationArgs,
65
parseMutationFilterArgs,
7-
parseQueryArgs,
86
updateState,
97
cloneDeep,
108
cloneDeepUnref,
@@ -18,23 +16,6 @@ describe("utils", () => {
1816
});
1917
});
2018

21-
describe("parseFilterArgs", () => {
22-
test("should default to empty filters", () => {
23-
const result = parseFilterArgs(undefined);
24-
25-
expect(result).toEqual({});
26-
});
27-
28-
test("should merge query key with filters", () => {
29-
const filters = { stale: true };
30-
31-
const result = parseFilterArgs(["key"], filters);
32-
const expected = { ...filters, queryKey: ["key"] };
33-
34-
expect(result).toEqual(expected);
35-
});
36-
});
37-
3819
describe("parseMutationArgs", () => {
3920
test("should return the same instance of options", () => {
4021
const options = { retry: false };
@@ -72,35 +53,6 @@ describe("utils", () => {
7253
});
7354
});
7455

75-
describe("parseQueryArgs", () => {
76-
test("should return the same instance of options", () => {
77-
const options = { retry: false };
78-
const result = parseQueryArgs(options);
79-
80-
expect(result).toStrictEqual(options);
81-
});
82-
83-
test("should merge query key with options", () => {
84-
const options = { retry: false };
85-
const result = parseQueryArgs(["key"], options);
86-
const expected = { ...options, queryKey: ["key"] };
87-
88-
expect(result).toEqual(expected);
89-
});
90-
91-
test("should merge query key and fn with options", () => {
92-
const options = { retry: false };
93-
const result = parseQueryArgs(["key"], simpleFetcher, options);
94-
const expected = {
95-
...options,
96-
queryKey: ["key"],
97-
queryFn: simpleFetcher,
98-
};
99-
100-
expect(result).toEqual(expected);
101-
});
102-
});
103-
10456
describe("parseMutationFilterArgs", () => {
10557
test("should default to empty filters", () => {
10658
const result = parseMutationFilterArgs(undefined);

src/vuejs/useIsFetching.ts

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { onScopeDispose, Ref, ref, watchEffect } from "vue-demi";
1+
import { onScopeDispose, Ref, ref, watch } from "vue-demi";
22
import type { QueryKey } from "react-query/lib/core";
33
import type { QueryFilters as QF } from "react-query/lib/core/utils";
44

55
import { useQueryClient } from "./useQueryClient";
6-
import { parseFilterArgs } from "./utils";
7-
import type { WithQueryClientKey } from "./types";
6+
import { cloneDeepUnref, isQueryKey } from "./utils";
7+
import type { MaybeRefDeep, WithQueryClientKey } from "./types";
88

9-
export type QueryFilters = WithQueryClientKey<QF>;
9+
export type QueryFilters = MaybeRefDeep<WithQueryClientKey<QF>>;
1010

1111
export function useIsFetching(filters?: QueryFilters): Ref<number>;
1212
export function useIsFetching(
@@ -17,26 +17,42 @@ export function useIsFetching(
1717
arg1?: QueryKey | QueryFilters,
1818
arg2?: QueryFilters
1919
): Ref<number> {
20-
const filters: Ref<QueryFilters> = ref({});
21-
const parsedFilters = parseFilterArgs(arg1, arg2);
22-
filters.value = parsedFilters;
20+
const filters = ref(parseFilterArgs(arg1, arg2));
21+
const queryClient = useQueryClient(filters.value.queryClientKey);
2322

24-
const queryClient = useQueryClient(parsedFilters.queryClientKey);
25-
26-
const isFetching = ref(queryClient.isFetching(filters.value));
23+
const isFetching = ref(queryClient.isFetching(filters));
2724

2825
const unsubscribe = queryClient.getQueryCache().subscribe(() => {
29-
isFetching.value = queryClient.isFetching(filters.value);
26+
isFetching.value = queryClient.isFetching(filters);
3027
});
3128

32-
watchEffect(() => {
33-
const parsedFiltersUpdate = parseFilterArgs(arg1, arg2);
34-
filters.value = parsedFiltersUpdate;
35-
});
29+
watch(
30+
[() => arg1, () => arg2],
31+
() => {
32+
filters.value = parseFilterArgs(arg1, arg2);
33+
isFetching.value = queryClient.isFetching(filters);
34+
},
35+
{ deep: true }
36+
);
3637

3738
onScopeDispose(() => {
3839
unsubscribe();
3940
});
4041

4142
return isFetching;
4243
}
44+
45+
export function parseFilterArgs(
46+
arg1?: QueryKey | QueryFilters,
47+
arg2: QueryFilters = {}
48+
) {
49+
let options: QueryFilters;
50+
51+
if (isQueryKey(arg1)) {
52+
options = { ...arg2, queryKey: arg1 };
53+
} else {
54+
options = arg1 || {};
55+
}
56+
57+
return cloneDeepUnref(options) as WithQueryClientKey<QF>;
58+
}

src/vuejs/utils.ts

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@ import type {
33
MutationFunction,
44
MutationKey,
55
MutationOptions,
6-
QueryFunction,
7-
QueryObserverOptions,
86
QueryKey,
97
} from "react-query/lib/core";
10-
import { isRef, reactive, toRefs, unref, UnwrapRef } from "vue-demi";
11-
import { QueryFilters } from "./useIsFetching";
8+
import { isRef, unref, UnwrapRef } from "vue-demi";
129
import { MutationFilters } from "./useIsMutating";
1310

1411
export const VUE_QUERY_CLIENT = "VUE_QUERY_CLIENT";
@@ -22,58 +19,6 @@ export function isQueryKey(value: unknown): value is QueryKey {
2219
return Array.isArray(value);
2320
}
2421

25-
// This Function is Deprecated. It's not used internally anymore.
26-
export function parseQueryArgs<
27-
TQueryFnData = unknown,
28-
TError = unknown,
29-
TData = TQueryFnData,
30-
TQueryKey extends QueryKey = QueryKey,
31-
TOptions = QueryObserverOptions<
32-
TQueryFnData,
33-
TError,
34-
TData,
35-
TQueryFnData,
36-
TQueryKey
37-
>
38-
>(
39-
arg1: QueryKey | TOptions,
40-
arg2: QueryFunction<TQueryFnData, TQueryKey> | TOptions = {} as TOptions,
41-
arg3: TOptions = {} as TOptions
42-
): TOptions {
43-
let options;
44-
45-
if (!isQueryKey(arg1)) {
46-
// `useQuery(optionsObj)`
47-
options = arg1;
48-
} else if (typeof arg2 === "function") {
49-
// `useQuery(queryKey, queryFn, optionsObj?)`
50-
options = {
51-
...toRefs(reactive(arg3 as unknown as object)),
52-
queryKey: arg1,
53-
queryFn: arg2,
54-
};
55-
} else {
56-
// `useQuery(queryKey, optionsObj?)`
57-
options = {
58-
...toRefs(reactive(arg2 as unknown as object)),
59-
queryKey: arg1,
60-
};
61-
}
62-
63-
return reactive(options as object) as unknown as TOptions;
64-
}
65-
66-
export function parseFilterArgs<TFilters extends QueryFilters>(
67-
arg1?: QueryKey | TFilters,
68-
arg2?: TFilters
69-
): TFilters {
70-
if (isQueryKey(arg1)) {
71-
return Object.assign(arg2 || ({} as TFilters), { queryKey: arg1 });
72-
}
73-
74-
return arg1 || ({} as TFilters);
75-
}
76-
7722
export function parseMutationArgs<
7823
TOptions extends MutationOptions<any, any, any, any>
7924
>(

0 commit comments

Comments
 (0)