From c1369911f7589ba4da80cee135af26f3a18a9fc7 Mon Sep 17 00:00:00 2001 From: 1cedrus Date: Mon, 10 Feb 2025 22:42:19 +0700 Subject: [PATCH 1/5] Integrate tanstack-query into useContractQuery --- packages/typink/package.json | 1 + packages/typink/src/hooks/useContractQuery.ts | 82 ++++--------------- .../typink/src/providers/TypinkProvider.tsx | 13 ++- yarn.lock | 19 +++++ 4 files changed, 43 insertions(+), 72 deletions(-) diff --git a/packages/typink/package.json b/packages/typink/package.json index fcb61ee0..0529c301 100644 --- a/packages/typink/package.json +++ b/packages/typink/package.json @@ -12,6 +12,7 @@ "test": "npx vitest --watch=false" }, "dependencies": { + "@tanstack/react-query": "^5.66.0", "dedot": "^0.6.1", "fast-deep-equal": "^3.1.3", "react": "^18.3.1", diff --git a/packages/typink/src/hooks/useContractQuery.ts b/packages/typink/src/hooks/useContractQuery.ts index 07b27c32..6dcb47e4 100644 --- a/packages/typink/src/hooks/useContractQuery.ts +++ b/packages/typink/src/hooks/useContractQuery.ts @@ -1,9 +1,10 @@ -import { useCallback, useEffect, useState } from 'react'; +import { useEffect } from 'react'; import { useDeepDeps } from './internal/index.js'; import { Args, OmitNever, Pop } from '../types.js'; import { Contract, ContractCallOptions, GenericContractApi } from 'dedot/contracts'; import { useTypink } from './useTypink.js'; import { Unsub } from 'dedot/types'; +import { useQuery } from '@tanstack/react-query'; type ContractQuery = OmitNever<{ [K in keyof A['query']]: K extends string ? (K extends `${infer Literal}` ? Literal : never) : never; @@ -49,71 +50,16 @@ export function useContractQuery< watch?: boolean; } & Args>>, ): UseContractQueryReturnType { - // TODO replace loading tracking state with tanstack - const { client } = useTypink(); - - const [isLoading, setIsLoading] = useState(true); - const [isRefreshing, setIsRefreshing] = useState(false); - const [result, setResult] = useState(); - const [error, setError] = useState(); - const { contract, fn, args = [], options, watch = false } = parameters; - const deps = useDeepDeps([contract, fn, args, options]); - - useEffect(() => { - let mounted = true; - - const fetchData = async () => { - if (!contract || !fn || !args) return; - - try { - setIsLoading(true); - - const result = await contract.query[fn](...args, options); - - if (mounted) { - setResult(result); - setError(undefined); - setIsLoading(false); - } - } catch (error: any) { - console.error('Error in contract query:', error); - if (mounted) { - setResult(undefined); - setError(error); - setIsLoading(false); - } - } - }; - - fetchData().catch(console.error); - - return () => { - mounted = false; - }; - }, deps); - - const refresh = useCallback(async () => { - if (!contract || !fn || !args) return; - - try { - setIsRefreshing(true); - - const result = await contract.query[fn](...args, options); - - setResult(result); - setError(undefined); - setIsRefreshing(false); - } catch (error: any) { - console.error('Error when refreshing the query:', error); - - setResult(undefined); - setError(error); - setIsRefreshing(false); - } - }, deps); + const { isLoading, error, isRefetching, data, refetch } = useQuery({ + queryKey: [fn, contract?.address, args, options], + queryFn: async () => { + if (!contract || !fn || !args) return {}; + return await contract.query[fn](...args, options); + }, + }); useEffect( () => { @@ -124,7 +70,7 @@ export function useContractQuery< client.query.system .number((_) => { - refresh(); + refetch(); }) .then((x) => { if (done) { @@ -140,14 +86,14 @@ export function useContractQuery< unsub && unsub(); }; }, - useDeepDeps([client, refresh, watch]), + useDeepDeps([client, refetch, watch]), ); return { isLoading, - refresh, - isRefreshing, - ...(result || {}), + refresh: refetch, + isRefreshing: isRefetching, + ...(data || {}), error, } as any; } diff --git a/packages/typink/src/providers/TypinkProvider.tsx b/packages/typink/src/providers/TypinkProvider.tsx index 264a0464..8c946177 100644 --- a/packages/typink/src/providers/TypinkProvider.tsx +++ b/packages/typink/src/providers/TypinkProvider.tsx @@ -9,6 +9,7 @@ import { WalletSetupProviderProps, } from './WalletSetupProvider.js'; import { TypinkEventsContextProps, TypinkEventsProvider, useTypinkEvents } from './TypinkEventsProvider.js'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; export interface TypinkContextProps extends ClientContextProps, @@ -26,7 +27,7 @@ export interface TypinkProviderProps extends ClientProviderProps, WalletSetupPro defaultCaller: SubstrateAddress; } -export type TypinkProviderInnerProps = Omit +export type TypinkProviderInnerProps = Omit; function TypinkProviderInner({ children, deployments, defaultCaller }: TypinkProviderInnerProps) { const clientContext = useClient(); @@ -49,6 +50,8 @@ function TypinkProviderInner({ children, deployments, defaultCaller }: TypinkPro ); } +const queryClient = new QueryClient(); + /** * TypinkProvider is the main provider component for the Typink application. * It wraps other providers (WalletSetupProvider, ClientProvider ...) to provide a complete context for the application. @@ -90,9 +93,11 @@ export function TypinkProvider({ cacheMetadata={cacheMetadata} supportedNetworks={supportedNetworks}> - - {children} - + + + {children} + + diff --git a/yarn.lock b/yarn.lock index 6d8175a2..74faae77 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4792,6 +4792,24 @@ __metadata: languageName: node linkType: hard +"@tanstack/query-core@npm:5.66.0": + version: 5.66.0 + resolution: "@tanstack/query-core@npm:5.66.0" + checksum: 10/ba8623c0272e36d3ce616afa024d43e07e6b69170219b32eb4f60156fee9ac4ffa74d2fbb999739b6dea757b75966e76129271f4224f06c59deee24a72944da4 + languageName: node + linkType: hard + +"@tanstack/react-query@npm:^5.66.0": + version: 5.66.0 + resolution: "@tanstack/react-query@npm:5.66.0" + dependencies: + "@tanstack/query-core": "npm:5.66.0" + peerDependencies: + react: ^18 || ^19 + checksum: 10/482decc02664e756c66c9ff46279b5eb3f0fb29fcdcb51b96319e8487a2b2e8b151319d6a5d9ef1180523a1792d6449cec2e9bfa87f37a4f755fc9d95534585d + languageName: node + linkType: hard + "@testing-library/dom@npm:^10.4.0": version: 10.4.0 resolution: "@testing-library/dom@npm:10.4.0" @@ -14130,6 +14148,7 @@ __metadata: version: 0.0.0-use.local resolution: "typink@workspace:packages/typink" dependencies: + "@tanstack/react-query": "npm:^5.66.0" "@types/react": "npm:^18.3.18" dedot: "npm:^0.6.1" fast-deep-equal: "npm:^3.1.3" From be1854c5fe64d945176b844461c946d4d5ac4619 Mon Sep 17 00:00:00 2001 From: 1cedrus Date: Tue, 11 Feb 2025 16:14:08 +0700 Subject: [PATCH 2/5] =?UTF-8?q?Refactor=20&=20Update=20tests=20?= =?UTF-8?q?=F0=9F=8E=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- e2e/zombienet/package.json | 1 + e2e/zombienet/src/utils.tsx | 5 +- packages/typink/package.json | 4 +- .../typink/src/hooks/__tests__/test-utils.tsx | 5 + .../hooks/__tests__/useContractQuery.test.ts | 203 ++++++++++-------- packages/typink/src/hooks/useContractQuery.ts | 15 +- .../typink/src/providers/TypinkProvider.tsx | 10 +- packages/typink/src/utils/misc.ts | 4 + yarn.lock | 4 +- 9 files changed, 145 insertions(+), 106 deletions(-) diff --git a/e2e/zombienet/package.json b/e2e/zombienet/package.json index 7edfbe43..10637869 100644 --- a/e2e/zombienet/package.json +++ b/e2e/zombienet/package.json @@ -11,6 +11,7 @@ "@polkadot/keyring": "^13.3.1", "@polkadot/types": "^15.4.1", "@polkadot/util-crypto": "^13.3.1", + "@tanstack/react-query": "^5.66.0", "dedot": "^0.6.1", "happy-dom": "^15.11.7", "typink": "workspace:*" diff --git a/e2e/zombienet/src/utils.tsx b/e2e/zombienet/src/utils.tsx index c11a9b2e..2487596e 100644 --- a/e2e/zombienet/src/utils.tsx +++ b/e2e/zombienet/src/utils.tsx @@ -11,6 +11,7 @@ import { assert, deferred } from 'dedot/utils'; import { cryptoWaitReady } from '@polkadot/util-crypto'; import { KeyringPair } from '@polkadot/keyring/types'; import { TypeRegistry } from '@polkadot/types'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; await cryptoWaitReady(); export const KEYRING = new Keyring({ type: 'sr25519' }); @@ -39,6 +40,8 @@ export const mockSigner = { }, } as InjectedSigner; +export const QUERY_CLIENT = new QueryClient(); + export const Wrapper = ({ children, deployments = [] }: Props) => ( ( signer={mockSigner} connectedAccount={{ address: ALICE }} appName='Typink Test App'> - {children} + {children} ); diff --git a/packages/typink/package.json b/packages/typink/package.json index 0529c301..0cc460b1 100644 --- a/packages/typink/package.json +++ b/packages/typink/package.json @@ -12,12 +12,14 @@ "test": "npx vitest --watch=false" }, "dependencies": { - "@tanstack/react-query": "^5.66.0", "dedot": "^0.6.1", "fast-deep-equal": "^3.1.3", "react": "^18.3.1", "react-use": "^17.6.0" }, + "peerDependencies": { + "@tanstack/react-query": "^5.66.0" + }, "devDependencies": { "@types/react": "^18.3.18" }, diff --git a/packages/typink/src/hooks/__tests__/test-utils.tsx b/packages/typink/src/hooks/__tests__/test-utils.tsx index 6fa755a9..1884d7c0 100644 --- a/packages/typink/src/hooks/__tests__/test-utils.tsx +++ b/packages/typink/src/hooks/__tests__/test-utils.tsx @@ -1,6 +1,7 @@ import { act } from '@testing-library/react'; import { Props } from '../../types.js'; import { TypinkEventsProvider } from '../../providers/index.js'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; export const waitForNextUpdate = async (then?: () => Promise) => { await act(async () => { @@ -14,3 +15,7 @@ export const sleep = (ms: number = 0) => { }; export const typinkEventsWrapper = ({ children }: Props) => {children}; + +export const queryClientWrapper = ({ children }: Props) => ( + {children} +); diff --git a/packages/typink/src/hooks/__tests__/useContractQuery.test.ts b/packages/typink/src/hooks/__tests__/useContractQuery.test.ts index 0818dc8d..09650522 100644 --- a/packages/typink/src/hooks/__tests__/useContractQuery.test.ts +++ b/packages/typink/src/hooks/__tests__/useContractQuery.test.ts @@ -2,7 +2,7 @@ import { act, renderHook, waitFor } from '@testing-library/react'; import { useContractQuery } from '../useContractQuery.js'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { Contract } from 'dedot/contracts'; -import { waitForNextUpdate } from './test-utils.js'; +import { queryClientWrapper, waitForNextUpdate } from './test-utils.js'; import { useTypink } from '../useTypink.js'; // Mock the external dependencies @@ -48,12 +48,14 @@ describe('useContractQuery', () => { }); it('should return loading state initially', () => { - const { result } = renderHook(() => - useContractQuery({ - contract, - // @ts-ignore - fn: 'testFunction', - }), + const { result } = renderHook( + () => + useContractQuery({ + contract, + // @ts-ignore + fn: 'testFunction', + }), + { wrapper: queryClientWrapper }, ); expect(result.current.isLoading).toBe(true); @@ -63,14 +65,16 @@ describe('useContractQuery', () => { contract.query.testFunction.mockResolvedValue({ data: 'test result' }); await act(async () => { - renderHook(() => - useContractQuery({ - contract, - // @ts-ignore - fn: 'testFunction', - args: ['arg1', 'arg2'], - options: { gasLimit: { refTime: 1000000n, proofSize: 1000000n } }, - }), + renderHook( + () => + useContractQuery({ + contract, + // @ts-ignore + fn: 'testFunction', + args: ['arg1', 'arg2'], + options: { gasLimit: { refTime: 1000000n, proofSize: 1000000n } }, + }), + { wrapper: queryClientWrapper }, ); }); @@ -82,12 +86,14 @@ describe('useContractQuery', () => { it('should update the result and loading state after query resolves', async () => { contract.query.testFunction.mockResolvedValue({ data: 'test result' }); - const { result } = renderHook(() => - useContractQuery({ - contract, - // @ts-ignore - fn: 'testFunction', - }), + const { result } = renderHook( + () => + useContractQuery({ + contract, + // @ts-ignore + fn: 'testFunction', + }), + { wrapper: queryClientWrapper }, ); await act(async () => { @@ -99,16 +105,16 @@ describe('useContractQuery', () => { }); it('should not call query function if contract is undefined', async () => { - const { result } = renderHook(() => - useContractQuery({ - contract: undefined, - // @ts-ignore - fn: 'testFunction', - }), + const { result } = renderHook( + () => + useContractQuery({ + contract: undefined, + // @ts-ignore + fn: 'testFunction', + }), + { wrapper: queryClientWrapper }, ); - await waitForNextUpdate(); - expect(result.current.isLoading).toBe(true); expect(contract.query.testFunction).not.toHaveBeenCalled(); }); @@ -116,21 +122,21 @@ describe('useContractQuery', () => { it('should refresh when refresh function is called', async () => { contract.query.testFunction.mockResolvedValue({ data: 'test result' }); - const { result } = renderHook(() => - useContractQuery({ - contract, - // @ts-ignore - fn: 'testFunction', - }), + const { result } = renderHook( + () => + useContractQuery({ + contract, + // @ts-ignore + fn: 'testFunction', + }), + { wrapper: queryClientWrapper }, ); - await waitForNextUpdate(async () => { - result.current.refresh(); - }); + await waitForNextUpdate(); + result.current.refresh(); - await waitForNextUpdate(async () => { - result.current.refresh(); - }); + await waitForNextUpdate(); + result.current.refresh(); expect(contract.query.testFunction).toHaveBeenCalledTimes(3); }); @@ -144,47 +150,54 @@ describe('useContractQuery', () => { }); }); - const { result } = renderHook(() => - useContractQuery({ - contract, - // @ts-ignore - fn: 'testFunction', - }), + const { result } = renderHook( + () => + useContractQuery({ + contract, + // @ts-ignore + fn: 'testFunction', + }), + { wrapper: queryClientWrapper }, ); - expect(result.current.isRefreshing).toBe(false); - - await act(async () => { - result.current.refresh(); + await waitFor(() => { + expect(result.current.isLoading).toBe(false); }); - expect(result.current.isRefreshing).toBe(true); + result.current.refresh(); + + await waitFor(() => { + expect(result.current.isRefreshing).toBe(true); + }); await waitFor(() => { expect(result.current.isRefreshing).toBe(false); expect(result.current.data).toBe('test result'); }); - }), - it('should handle errors from the contract query', async () => { - const testError = new Error('Test error'); - contract.query.testFunction.mockRejectedValue(testError); + }); + + it('should handle errors from the contract query', async () => { + const testError = new Error('Test error'); + contract.query.testFunction.mockRejectedValue(testError); - const { result } = renderHook(() => + const { result } = renderHook( + () => useContractQuery({ contract, // @ts-ignore fn: 'testFunction', }), - ); + { wrapper: queryClientWrapper }, + ); - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 0)); - }); + expect(result.current.isLoading).toBe(true); + await waitFor(() => { expect(result.current.isLoading).toBe(false); expect(result.current.error).toBe(testError); expect(result.current.data).toBeUndefined(); }); + }); it('should reset error state on successful query after an error', async () => { const testError = new Error('Test error'); @@ -192,42 +205,44 @@ describe('useContractQuery', () => { .mockRejectedValueOnce(testError) .mockResolvedValueOnce({ data: 'success after error' }); - const { result } = renderHook(() => - useContractQuery({ - contract, - // @ts-ignore - fn: 'testFunction', - }), + const { result } = renderHook( + () => + useContractQuery({ + contract, + // @ts-ignore + fn: 'testFunction', + }), + { wrapper: queryClientWrapper }, ); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + expect(result.current.error).toBe(testError); + expect(result.current.data).toBeUndefined(); + }); - expect(result.current.isLoading).toBe(false); - expect(result.current.error).toBe(testError); - expect(result.current.data).toBeUndefined(); + result.current.refresh(); - await waitForNextUpdate(async () => { - result.current.refresh(); + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + expect(result.current.error).toBeNull(); + expect(result.current.data).toEqual('success after error'); }); - - expect(result.current.isLoading).toBe(false); - expect(result.current.error).toBeUndefined(); - expect(result.current.data).toEqual('success after error'); }); it('should maintain states if contract is undefined', async () => { - const { result } = renderHook(() => - useContractQuery({ - contract: undefined, - // @ts-ignore - fn: 'testFunction', - }), + const { result } = renderHook( + () => + useContractQuery({ + contract: undefined, + // @ts-ignore + fn: 'testFunction', + }), + { wrapper: queryClientWrapper }, ); - await waitForNextUpdate(); - expect(result.current.isLoading).toBe(true); - expect(result.current.error).toBeUndefined(); + expect(result.current.error).toBeNull(); expect(result.current.data).toBeUndefined(); }); @@ -246,13 +261,15 @@ describe('useContractQuery', () => { }); }); - const { result } = renderHook(() => - useContractQuery({ - contract, - // @ts-ignore - fn: 'message', - watch: true, - }), + const { result } = renderHook( + () => + useContractQuery({ + contract, + // @ts-ignore + fn: 'message', + watch: true, + }), + { wrapper: queryClientWrapper }, ); await waitForNextUpdate(); diff --git a/packages/typink/src/hooks/useContractQuery.ts b/packages/typink/src/hooks/useContractQuery.ts index 6dcb47e4..26e90047 100644 --- a/packages/typink/src/hooks/useContractQuery.ts +++ b/packages/typink/src/hooks/useContractQuery.ts @@ -5,6 +5,7 @@ import { Contract, ContractCallOptions, GenericContractApi } from 'dedot/contrac import { useTypink } from './useTypink.js'; import { Unsub } from 'dedot/types'; import { useQuery } from '@tanstack/react-query'; +import { stringify } from '../utils/misc.js'; type ContractQuery = OmitNever<{ [K in keyof A['query']]: K extends string ? (K extends `${infer Literal}` ? Literal : never) : never; @@ -54,11 +55,19 @@ export function useContractQuery< const { contract, fn, args = [], options, watch = false } = parameters; const { isLoading, error, isRefetching, data, refetch } = useQuery({ - queryKey: [fn, contract?.address, args, options], + // TODO!: Stringify a contract is not efficient, pick important fields only + queryKey: [fn!, stringify(contract), stringify(args), stringify(options)], queryFn: async () => { - if (!contract || !fn || !args) return {}; - return await contract.query[fn](...args, options); + if (!client || !contract) return {}; + + try { + return await contract.query[fn](...args, options); + } catch (error) { + throw error; + } }, + // Temporary until we allow retry in the future, if enabled the error will not be updated immediately + retry: false, }); useEffect( diff --git a/packages/typink/src/providers/TypinkProvider.tsx b/packages/typink/src/providers/TypinkProvider.tsx index 8c946177..9083934a 100644 --- a/packages/typink/src/providers/TypinkProvider.tsx +++ b/packages/typink/src/providers/TypinkProvider.tsx @@ -50,8 +50,6 @@ function TypinkProviderInner({ children, deployments, defaultCaller }: TypinkPro ); } -const queryClient = new QueryClient(); - /** * TypinkProvider is the main provider component for the Typink application. * It wraps other providers (WalletSetupProvider, ClientProvider ...) to provide a complete context for the application. @@ -93,11 +91,9 @@ export function TypinkProvider({ cacheMetadata={cacheMetadata} supportedNetworks={supportedNetworks}> - - - {children} - - + + {children} + diff --git a/packages/typink/src/utils/misc.ts b/packages/typink/src/utils/misc.ts index f2d5e31d..9b7f8163 100644 --- a/packages/typink/src/utils/misc.ts +++ b/packages/typink/src/utils/misc.ts @@ -1 +1,5 @@ export const noop = () => {}; + +export const stringify = (obj: any) => { + return JSON.stringify(obj, (_, value) => (typeof value === 'bigint' ? value.toString() : value)); +}; diff --git a/yarn.lock b/yarn.lock index 74faae77..84466811 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14148,12 +14148,13 @@ __metadata: version: 0.0.0-use.local resolution: "typink@workspace:packages/typink" dependencies: - "@tanstack/react-query": "npm:^5.66.0" "@types/react": "npm:^18.3.18" dedot: "npm:^0.6.1" fast-deep-equal: "npm:^3.1.3" react: "npm:^18.3.1" react-use: "npm:^17.6.0" + peerDependencies: + "@tanstack/react-query": ^5.66.0 languageName: unknown linkType: soft @@ -15156,6 +15157,7 @@ __metadata: "@polkadot/keyring": "npm:^13.3.1" "@polkadot/types": "npm:^15.4.1" "@polkadot/util-crypto": "npm:^13.3.1" + "@tanstack/react-query": "npm:^5.66.0" dedot: "npm:^0.6.1" happy-dom: "npm:^15.11.7" typink: "workspace:*" From 93b5c0a33abde48e82d9aac09268228588fd3d36 Mon Sep 17 00:00:00 2001 From: 1cedrus Date: Tue, 11 Feb 2025 16:19:16 +0700 Subject: [PATCH 3/5] Remove unused import --- packages/typink/src/providers/TypinkProvider.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/typink/src/providers/TypinkProvider.tsx b/packages/typink/src/providers/TypinkProvider.tsx index 9083934a..58e5e5e5 100644 --- a/packages/typink/src/providers/TypinkProvider.tsx +++ b/packages/typink/src/providers/TypinkProvider.tsx @@ -9,7 +9,6 @@ import { WalletSetupProviderProps, } from './WalletSetupProvider.js'; import { TypinkEventsContextProps, TypinkEventsProvider, useTypinkEvents } from './TypinkEventsProvider.js'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; export interface TypinkContextProps extends ClientContextProps, From 3085d3af4c78869ff8c4ae83d64f62788ea041d3 Mon Sep 17 00:00:00 2001 From: 1cedrus Date: Tue, 11 Feb 2025 16:39:44 +0700 Subject: [PATCH 4/5] Not to stringify contract --- packages/typink/src/hooks/useContractQuery.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typink/src/hooks/useContractQuery.ts b/packages/typink/src/hooks/useContractQuery.ts index 26e90047..e0a8e3c9 100644 --- a/packages/typink/src/hooks/useContractQuery.ts +++ b/packages/typink/src/hooks/useContractQuery.ts @@ -56,7 +56,7 @@ export function useContractQuery< const { isLoading, error, isRefetching, data, refetch } = useQuery({ // TODO!: Stringify a contract is not efficient, pick important fields only - queryKey: [fn!, stringify(contract), stringify(args), stringify(options)], + queryKey: [fn!, contract?.address, stringify(args), stringify(options)], queryFn: async () => { if (!client || !contract) return {}; From e4bb4d68e9291e0163ff610c7906eb1eb7b22a04 Mon Sep 17 00:00:00 2001 From: 1cedrus Date: Tue, 11 Feb 2025 17:20:45 +0700 Subject: [PATCH 5/5] Add client into queryKey --- e2e/zombienet/src/utils.tsx | 4 +--- packages/typink/src/hooks/useContractQuery.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/e2e/zombienet/src/utils.tsx b/e2e/zombienet/src/utils.tsx index 2487596e..2c766500 100644 --- a/e2e/zombienet/src/utils.tsx +++ b/e2e/zombienet/src/utils.tsx @@ -40,8 +40,6 @@ export const mockSigner = { }, } as InjectedSigner; -export const QUERY_CLIENT = new QueryClient(); - export const Wrapper = ({ children, deployments = [] }: Props) => ( ( signer={mockSigner} connectedAccount={{ address: ALICE }} appName='Typink Test App'> - {children} + {children} ); diff --git a/packages/typink/src/hooks/useContractQuery.ts b/packages/typink/src/hooks/useContractQuery.ts index e0a8e3c9..3f9c8257 100644 --- a/packages/typink/src/hooks/useContractQuery.ts +++ b/packages/typink/src/hooks/useContractQuery.ts @@ -56,7 +56,7 @@ export function useContractQuery< const { isLoading, error, isRefetching, data, refetch } = useQuery({ // TODO!: Stringify a contract is not efficient, pick important fields only - queryKey: [fn!, contract?.address, stringify(args), stringify(options)], + queryKey: [fn!, !!client, contract?.address, stringify(args), stringify(options)], queryFn: async () => { if (!client || !contract) return {};