Skip to content

Commit f1066d0

Browse files
committed
feat: useIsMutating reactivity improvements
1 parent f7a98b6 commit f1066d0

File tree

7 files changed

+204
-146
lines changed

7 files changed

+204
-146
lines changed

src/vuejs/__tests__/useIsFetching.test.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,6 @@ 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-
5431
test("should stop listening to changes on onScopeDispose", async () => {
5532
const onScopeDisposeMock = onScopeDispose as jest.MockedFunction<
5633
typeof onScopeDispose
@@ -76,6 +53,29 @@ describe("useIsFetching", () => {
7653
onScopeDisposeMock.mockReset();
7754
});
7855

56+
test("should properly update filters", async () => {
57+
const filter = reactive({ stale: false });
58+
useQuery(
59+
["isFetching"],
60+
() =>
61+
new Promise((resolve) => {
62+
setTimeout(() => {
63+
return resolve("Some data");
64+
}, 100);
65+
})
66+
);
67+
const isFetching = useIsFetching(filter);
68+
69+
expect(isFetching.value).toStrictEqual(0);
70+
71+
filter.stale = true;
72+
await flushPromises();
73+
74+
expect(isFetching.value).toStrictEqual(1);
75+
76+
await flushPromises(100);
77+
});
78+
7979
describe("parseFilterArgs", () => {
8080
test("should default to empty filters", () => {
8181
const result = parseFilterArgs(undefined);

src/vuejs/__tests__/useIsMutating.test.ts

Lines changed: 37 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, successMutator } from "./test-utils";
44
import { useMutation } from "../useMutation";
5-
import { useIsMutating } from "../useIsMutating";
5+
import { parseMutationFilterArgs, useIsMutating } from "../useIsMutating";
66
import { useQueryClient } from "../useQueryClient";
77

88
jest.mock("../useQueryClient");
@@ -63,4 +63,39 @@ describe("useIsMutating", () => {
6363

6464
expect(useQueryClient).toHaveBeenCalledWith(queryClientKey);
6565
});
66+
67+
test("should properly update filters", async () => {
68+
const filter = reactive({ mutationKey: ["foo"] });
69+
const { mutate } = useMutation(["isMutating"], (params: string) =>
70+
successMutator(params)
71+
);
72+
mutate("foo");
73+
74+
const isMutating = useIsMutating(filter);
75+
76+
expect(isMutating.value).toStrictEqual(0);
77+
78+
filter.mutationKey = ["isMutating"];
79+
80+
await flushPromises();
81+
82+
expect(isMutating.value).toStrictEqual(1);
83+
});
84+
85+
describe("parseMutationFilterArgs", () => {
86+
test("should default to empty filters", () => {
87+
const result = parseMutationFilterArgs(undefined);
88+
89+
expect(result).toEqual({});
90+
});
91+
92+
test("should merge mutation key with filters", () => {
93+
const filters = { fetching: true };
94+
95+
const result = parseMutationFilterArgs(["key"], filters);
96+
const expected = { ...filters, mutationKey: ["key"] };
97+
98+
expect(result).toEqual(expected);
99+
});
100+
});
66101
});

src/vuejs/__tests__/useMutation.test.ts

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import { reactive } from "vue-demi";
12
import { errorMutator, flushPromises, successMutator } from "./test-utils";
2-
import { useMutation } from "../useMutation";
3+
import { parseMutationArgs, useMutation } from "../useMutation";
4+
import { useQueryClient } from "../useQueryClient";
35

46
jest.mock("../useQueryClient");
57

@@ -70,6 +72,26 @@ describe("useMutation", () => {
7072
});
7173
});
7274

75+
test("should update reactive options", async () => {
76+
const queryClient = useQueryClient();
77+
const mutationCache = queryClient.getMutationCache();
78+
const options = reactive({ mutationKey: ["foo"] });
79+
const mutation = useMutation(
80+
(params: string) => successMutator(params),
81+
options
82+
);
83+
84+
options.mutationKey = ["bar"];
85+
await flushPromises();
86+
mutation.mutate("xyz");
87+
88+
await flushPromises();
89+
90+
const mutations = mutationCache.find({ mutationKey: ["bar"] });
91+
92+
expect(mutations?.options.mutationKey).toEqual(["bar"]);
93+
});
94+
7395
test("should reset state after invoking mutation.reset", async () => {
7496
const mutation = useMutation((params: string) => errorMutator(params));
7597

@@ -231,4 +253,41 @@ describe("useMutation", () => {
231253
});
232254
});
233255
});
256+
257+
describe("parseMutationArgs", () => {
258+
test("should return the same instance of options", () => {
259+
const options = { retry: false };
260+
const result = parseMutationArgs(options);
261+
262+
expect(result).toEqual(options);
263+
});
264+
265+
test("should merge query key with options", () => {
266+
const options = { retry: false };
267+
const result = parseMutationArgs(["key"], options);
268+
const expected = { ...options, mutationKey: ["key"] };
269+
270+
expect(result).toEqual(expected);
271+
});
272+
273+
test("should merge query fn with options", () => {
274+
const options = { retry: false };
275+
const result = parseMutationArgs(successMutator, options);
276+
const expected = { ...options, mutationFn: successMutator };
277+
278+
expect(result).toEqual(expected);
279+
});
280+
281+
test("should merge query key and fn with options", () => {
282+
const options = { retry: false };
283+
const result = parseMutationArgs(["key"], successMutator, options);
284+
const expected = {
285+
...options,
286+
mutationKey: ["key"],
287+
mutationFn: successMutator,
288+
};
289+
290+
expect(result).toEqual(expected);
291+
});
292+
});
234293
});

src/vuejs/__tests__/utils.test.ts

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
1-
import { successMutator } from "./test-utils";
2-
import {
3-
isQueryKey,
4-
parseMutationArgs,
5-
parseMutationFilterArgs,
6-
updateState,
7-
cloneDeep,
8-
cloneDeepUnref,
9-
} from "../utils";
1+
import { isQueryKey, updateState, cloneDeep, cloneDeepUnref } from "../utils";
102
import { reactive, ref } from "vue-demi";
113

124
describe("utils", () => {
@@ -16,60 +8,6 @@ describe("utils", () => {
168
});
179
});
1810

19-
describe("parseMutationArgs", () => {
20-
test("should return the same instance of options", () => {
21-
const options = { retry: false };
22-
const result = parseMutationArgs(options);
23-
24-
expect(result).toEqual(options);
25-
});
26-
27-
test("should merge query key with options", () => {
28-
const options = { retry: false };
29-
const result = parseMutationArgs(["key"], options);
30-
const expected = { ...options, mutationKey: ["key"] };
31-
32-
expect(result).toEqual(expected);
33-
});
34-
35-
test("should merge query fn with options", () => {
36-
const options = { retry: false };
37-
const result = parseMutationArgs(successMutator, options);
38-
const expected = { ...options, mutationFn: successMutator };
39-
40-
expect(result).toEqual(expected);
41-
});
42-
43-
test("should merge query key and fn with options", () => {
44-
const options = { retry: false };
45-
const result = parseMutationArgs(["key"], successMutator, options);
46-
const expected = {
47-
...options,
48-
mutationKey: ["key"],
49-
mutationFn: successMutator,
50-
};
51-
52-
expect(result).toEqual(expected);
53-
});
54-
});
55-
56-
describe("parseMutationFilterArgs", () => {
57-
test("should default to empty filters", () => {
58-
const result = parseMutationFilterArgs(undefined);
59-
60-
expect(result).toEqual(undefined);
61-
});
62-
63-
test("should merge mutation key with filters", () => {
64-
const filters = { fetching: true };
65-
66-
const result = parseMutationFilterArgs(["key"], filters);
67-
const expected = { ...filters, mutationKey: ["key"] };
68-
69-
expect(result).toEqual(expected);
70-
});
71-
});
72-
7311
describe("updateState", () => {
7412
test("should update first object with values from the second one", () => {
7513
const origin = { option1: "a", option2: "b", option3: "c" };

src/vuejs/useIsMutating.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { onScopeDispose, Ref, ref } from "vue-demi";
1+
import { onScopeDispose, Ref, ref, watch } from "vue-demi";
22
import type { MutationKey } from "react-query/lib/core";
33
import type { MutationFilters as MF } from "react-query/lib/core/utils";
44

55
import { useQueryClient } from "./useQueryClient";
6-
import { parseMutationFilterArgs } 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 MutationFilters = WithQueryClientKey<MF>;
9+
export type MutationFilters = MaybeRefDeep<WithQueryClientKey<MF>>;
1010

1111
export function useIsMutating(filters?: MutationFilters): Ref<number>;
1212
export function useIsMutating(
@@ -17,18 +17,42 @@ export function useIsMutating(
1717
arg1?: MutationKey | MutationFilters,
1818
arg2?: Omit<MutationFilters, "mutationKey">
1919
): Ref<number> {
20-
const filters = parseMutationFilterArgs(arg1, arg2);
21-
const queryClient = useQueryClient(filters?.queryClientKey);
20+
const filters = ref(parseMutationFilterArgs(arg1, arg2));
21+
const queryClient = useQueryClient(filters.value.queryClientKey);
2222

2323
const isMutating = ref(queryClient.isMutating(filters));
2424

2525
const unsubscribe = queryClient.getMutationCache().subscribe(() => {
2626
isMutating.value = queryClient.isMutating(filters);
2727
});
2828

29+
watch(
30+
[() => arg1, () => arg2],
31+
() => {
32+
filters.value = parseMutationFilterArgs(arg1, arg2);
33+
isMutating.value = queryClient.isMutating(filters);
34+
},
35+
{ deep: true }
36+
);
37+
2938
onScopeDispose(() => {
3039
unsubscribe();
3140
});
3241

3342
return isMutating;
3443
}
44+
45+
export function parseMutationFilterArgs(
46+
arg1?: MutationKey | MutationFilters,
47+
arg2: MutationFilters = {}
48+
) {
49+
let options: MutationFilters;
50+
51+
if (isQueryKey(arg1)) {
52+
options = { ...arg2, mutationKey: arg1 };
53+
} else {
54+
options = arg1 || {};
55+
}
56+
57+
return cloneDeepUnref(options) as WithQueryClientKey<MF>;
58+
}

0 commit comments

Comments
 (0)