Repository: urql-graphql/urql
Pull request #3614 (2024-06-18 12:23:10)

fix(vue): variables lose reactivity
## Summary

Reverts #3612 and adds a test asserting this behavior for the future
Re-opens #3507

We need to identify what specifically causes #3507 to keep allocating new helpers, this might as well be a bug in Vue as multiple libraries seem to leverage this pattern of calling `reactive` on a top-level argument.

changeset-bot[bot]: ###  🦋  Changeset detected

Latest commit: e55fcb81d4e60bd692e7f33f5950a0c2bbed2164

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name      | Type  |
| --------- | ----- |
| @urql/vue | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/urql-graphql/urql/new/fix-variables-losing-reactivity?filename=.changeset/four-pillows-tan.md&value=---%0A%22%40urql%2Fvue%22%3A%20patch%0A---%0A%0Afix(vue)%3A%20variables%20lose%20reactivity%0A)



Patch:
diff --git a/.changeset/curvy-pets-yawn.md b/.changeset/curvy-pets-yawn.md
new file mode 100644
index 00000000..68f24297
--- /dev/null
+++ b/.changeset/curvy-pets-yawn.md
@@ -0,0 +1,5 @@
+---
+'@urql/vue': patch
+---
+
+Fix variables losing reactivity
diff --git a/packages/vue-urql/src/useQuery.ts b/packages/vue-urql/src/useQuery.ts
index 70ddd41a..0020074b 100644
--- a/packages/vue-urql/src/useQuery.ts
+++ b/packages/vue-urql/src/useQuery.ts
@@ -1,6 +1,7 @@
 /* eslint-disable react-hooks/rules-of-hooks */
 
 import type { Ref, WatchStopHandle } from 'vue';
+import { reactive } from 'vue';
 import { isRef, ref, shallowRef, watch, watchEffect } from 'vue';
 
 import type { Subscription, Source } from 'wonka';
@@ -241,10 +242,12 @@ export function useQuery<T = any, V extends AnyVariables = AnyVariables>(
 }
 
 export function callUseQuery<T = any, V extends AnyVariables = AnyVariables>(
-  args: UseQueryArgs<T, V>,
+  _args: UseQueryArgs<T, V>,
   client: Ref<Client> = useClient(),
   stops: WatchStopHandle[] = []
 ): UseQueryResponse<T, V> {
+  const args = reactive(_args) as UseQueryArgs<T, V>;
+
   const data: Ref<T | undefined> = ref();
   const stale: Ref<boolean> = ref(false);
   const fetching: Ref<boolean> = ref(false);


Test patch:
diff --git a/packages/vue-urql/src/useQuery.test.ts b/packages/vue-urql/src/useQuery.test.ts
index 5ba38be7..62abb2d9 100644
--- a/packages/vue-urql/src/useQuery.test.ts
+++ b/packages/vue-urql/src/useQuery.test.ts
@@ -108,6 +108,38 @@ describe('useQuery', () => {
     );
   });
 
+  it('reacts to variables changing', async () => {
+    const executeQuery = vi
+      .spyOn(client, 'executeQuery')
+      .mockImplementation(request => {
+        return pipe(
+          fromValue({ operation: request, data: { test: true } }),
+          delay(1)
+        ) as any;
+      });
+
+    const variables = {
+      test: ref(1),
+    };
+    const query$ = useQuery({
+      query: '{ test }',
+      variables,
+    });
+
+    await query$;
+
+    expect(executeQuery).toHaveBeenCalledTimes(1);
+
+    expect(query$.operation.value).toHaveProperty('variables.test', 1);
+
+    variables.test.value = 2;
+
+    await query$;
+
+    expect(executeQuery).toHaveBeenCalledTimes(2);
+    expect(query$.operation.value).toHaveProperty('variables.test', 2);
+  });
+
   it('pauses query when asked to do so', async () => {
     const subject = makeSubject<any>();
     const executeQuery = vi