Skip to content

Commit 51c8fed

Browse files
authored
fix(query): make queries work with Refs in queryKey array (#108)
* fix: make use-query working with Refs * docs: update
1 parent f3dbbaa commit 51c8fed

File tree

3 files changed

+44
-5
lines changed

3 files changed

+44
-5
lines changed

docs/guides/query-keys.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ useQuery(['todos', { type: 'done' }], ...)
3838
// queryKey === ['todos', { type: 'done' }]
3939
```
4040

41-
!> If your query key parameter **will change over time** in the same component, do not place it directly in the `queryKey` array. Place it inside an object as a `ref` and wrap the whole `queryKey` in `reactive`. This is due to how vue reactivity system works.
41+
!> If your query key parameter **will change over time** in the same component, pass every such query key parameter as a `ref` or computed value.
4242

4343
```js
4444
const id = ref(5);
45-
useQuery(reactive(['todo', { id }]), ...)
45+
useQuery(['todo', id], ...)
4646
```
4747

4848
### Query Keys are hashed deterministically!

src/vue/__tests__/useQuery.test.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ describe("useQuery", () => {
8484
});
8585
});
8686

87-
test("should update query on reactive prop change", async () => {
87+
test("should update query on reactive options object change", async () => {
8888
const spy = jest.fn();
8989
const onSuccess = ref(noop);
9090
useQuery(
@@ -103,6 +103,31 @@ describe("useQuery", () => {
103103
expect(spy).toBeCalledTimes(1);
104104
});
105105

106+
test("should update query on reactive (Ref) key change", async () => {
107+
const secondKeyRef = ref("key7");
108+
const query = useQuery(["key6", secondKeyRef], simpleFetcher);
109+
110+
await flushPromises();
111+
112+
expect(query).toMatchObject({
113+
status: { value: "success" },
114+
});
115+
116+
secondKeyRef.value = "key8";
117+
await flushPromises();
118+
119+
expect(query).toMatchObject({
120+
status: { value: "loading" },
121+
data: { value: undefined },
122+
});
123+
124+
await flushPromises();
125+
126+
expect(query).toMatchObject({
127+
status: { value: "success" },
128+
});
129+
});
130+
106131
test("should properly execute dependant queries", async () => {
107132
const { data } = useQuery("dependant1", simpleFetcher);
108133

src/vue/useBaseQuery.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ToRefs,
66
reactive,
77
watchEffect,
8+
unref,
89
} from "vue-demi";
910

1011
import type {
@@ -53,15 +54,19 @@ export function useBaseQuery<
5354
Observer: typeof QueryObserver
5455
): UseQueryReturnType<TData, TError> {
5556
const queryClient = useQueryClient(options.queryClientKey);
56-
const defaultedOptions = queryClient.defaultQueryObserverOptions(options);
57+
const defaultedOptions = queryClient.defaultQueryObserverOptions(
58+
getOptionsWithUnrefKey(options)
59+
);
5760
const observer = new Observer(queryClient, defaultedOptions);
5861
const state = reactive(observer.getCurrentResult());
5962
const unsubscribe = observer.subscribe((result) => {
6063
updateState(state, result);
6164
});
6265

6366
watchEffect(() => {
64-
observer.setOptions(queryClient.defaultQueryObserverOptions(options));
67+
observer.setOptions(
68+
queryClient.defaultQueryObserverOptions(getOptionsWithUnrefKey(options))
69+
);
6570
});
6671

6772
onUnmounted(() => {
@@ -80,4 +85,13 @@ export function useBaseQuery<
8085
...resultRefs,
8186
suspense,
8287
};
88+
89+
// We need to unref keys, otherwise ReactQuery doesn't recognise keys changes
90+
function getOptionsWithUnrefKey<
91+
T extends { queryKey?: QueryKey | undefined }
92+
>(options: T): T {
93+
return Array.isArray(options.queryKey)
94+
? { ...options, queryKey: options.queryKey.map(unref) }
95+
: options;
96+
}
8397
}

0 commit comments

Comments
 (0)