From 5b6765a3ef15c8d948639c8895658d2786afe968 Mon Sep 17 00:00:00 2001 From: gopnik5 Date: Thu, 10 Apr 2025 15:13:21 -0400 Subject: [PATCH 1/4] fix(solid-query): client() doesn't return undefined --- packages/solid-query/src/useBaseQuery.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/solid-query/src/useBaseQuery.ts b/packages/solid-query/src/useBaseQuery.ts index 0b504ed0a7..d6b967831c 100644 --- a/packages/solid-query/src/useBaseQuery.ts +++ b/packages/solid-query/src/useBaseQuery.ts @@ -116,7 +116,11 @@ export function useBaseQuery< ) { type ResourceData = QueryObserverResult - const client = createMemo(() => useQueryClient(queryClient?.())) + const client = createMemo( + () => useQueryClient(queryClient?.()), + useQueryClient(queryClient?.()), + ) + const isRestoring = useIsRestoring() // There are times when we run a query on the server but the resource is never read // This could lead to times when the queryObserver is unsubscribed before the resource has loaded From 3fde36d95e96d0de32a18bd032b421c5028a9d6a Mon Sep 17 00:00:00 2001 From: gopnik5 Date: Mon, 14 Apr 2025 10:42:39 -0400 Subject: [PATCH 2/4] fix: (query-broadcast-client-experimental) - removing query from one tab doesn't remove it from all tabs --- .../package.json | 2 + .../src/__tests__/index.test.ts | 28 +++++++++++++ .../src/index.ts | 39 +++++++++++++++---- packages/solid-query/src/useBaseQuery.ts | 5 +-- 4 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 packages/query-broadcast-client-experimental/src/__tests__/index.test.ts diff --git a/packages/query-broadcast-client-experimental/package.json b/packages/query-broadcast-client-experimental/package.json index c712f57afb..c25f0a19eb 100644 --- a/packages/query-broadcast-client-experimental/package.json +++ b/packages/query-broadcast-client-experimental/package.json @@ -28,6 +28,8 @@ "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js --build", "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js --build", "test:types:tscurrent": "tsc --build", + "test:lib": "vitest", + "test:lib:dev": "pnpm run test:lib --watch", "test:build": "publint --strict && attw --pack", "build": "tsup --tsconfig tsconfig.prod.json" }, diff --git a/packages/query-broadcast-client-experimental/src/__tests__/index.test.ts b/packages/query-broadcast-client-experimental/src/__tests__/index.test.ts new file mode 100644 index 0000000000..14686ac97b --- /dev/null +++ b/packages/query-broadcast-client-experimental/src/__tests__/index.test.ts @@ -0,0 +1,28 @@ +import { QueryClient } from '@tanstack/query-core' +import { beforeEach, describe, expect, it } from 'vitest' +import { broadcastQueryClient } from '..' +import type { QueryCache } from '@tanstack/query-core' + +describe('broadcastQueryClient', () => { + let queryClient: QueryClient + let queryCache: QueryCache + let unsubscribe: () => void + + beforeEach(() => { + queryClient = new QueryClient() + queryCache = queryClient.getQueryCache() + }) + + it('should subscribe to the query cache', async () => { + unsubscribe = broadcastQueryClient({ + queryClient, + broadcastChannel: 'test_channel', + }) + expect(queryCache.hasListeners()).toBe(true) + }) + + it('should not have any listeners after cleanup', async () => { + unsubscribe() + expect(queryCache.hasListeners()).toBe(false) + }) +}) diff --git a/packages/query-broadcast-client-experimental/src/index.ts b/packages/query-broadcast-client-experimental/src/index.ts index f49a09b7ef..e102b3c0b0 100644 --- a/packages/query-broadcast-client-experimental/src/index.ts +++ b/packages/query-broadcast-client-experimental/src/index.ts @@ -12,7 +12,7 @@ export function broadcastQueryClient({ queryClient, broadcastChannel = 'tanstack-query', options, -}: BroadcastQueryClientOptions) { +}: BroadcastQueryClientOptions): () => void { let transaction = false const tx = (cb: () => void) => { transaction = true @@ -27,13 +27,13 @@ export function broadcastQueryClient({ const queryCache = queryClient.getQueryCache() - queryClient.getQueryCache().subscribe((queryEvent) => { + const unsubscribe = queryClient.getQueryCache().subscribe((queryEvent) => { if (transaction) { return } const { - query: { queryHash, queryKey, state }, + query: { queryHash, queryKey, state, observers }, } = queryEvent if (queryEvent.type === 'updated' && queryEvent.action.type === 'success') { @@ -45,13 +45,21 @@ export function broadcastQueryClient({ }) } - if (queryEvent.type === 'removed') { + if (queryEvent.type === 'removed' && observers.length > 0) { channel.postMessage({ type: 'removed', queryHash, queryKey, }) } + + if (queryEvent.type === 'added') { + channel.postMessage({ + type: 'added', + queryHash, + queryKey, + }) + } }) channel.onmessage = (action) => { @@ -62,9 +70,9 @@ export function broadcastQueryClient({ tx(() => { const { type, queryHash, queryKey, state } = action - if (type === 'updated') { - const query = queryCache.get(queryHash) + const query = queryCache.get(queryHash) + if (type === 'updated') { if (query) { query.setState(state) return @@ -79,12 +87,27 @@ export function broadcastQueryClient({ state, ) } else if (type === 'removed') { - const query = queryCache.get(queryHash) - if (query) { queryCache.remove(query) } + } else if (type === 'added') { + if (query) { + query.setState(state) + return + } + queryCache.build( + queryClient, + { + queryKey, + queryHash, + }, + state, + ) } }) } + return () => { + unsubscribe() + channel.close() + } } diff --git a/packages/solid-query/src/useBaseQuery.ts b/packages/solid-query/src/useBaseQuery.ts index d6b967831c..c77c6afa56 100644 --- a/packages/solid-query/src/useBaseQuery.ts +++ b/packages/solid-query/src/useBaseQuery.ts @@ -116,10 +116,7 @@ export function useBaseQuery< ) { type ResourceData = QueryObserverResult - const client = createMemo( - () => useQueryClient(queryClient?.()), - useQueryClient(queryClient?.()), - ) + const client = createMemo(() => useQueryClient(queryClient?.())) const isRestoring = useIsRestoring() // There are times when we run a query on the server but the resource is never read From 5c92384d0b8e7ba672316457cd6391224dbb7d76 Mon Sep 17 00:00:00 2001 From: gopnik5 Date: Mon, 14 Apr 2025 11:05:58 -0400 Subject: [PATCH 3/4] fix: (query-broadcast-client-experimental) - removing query from one tab doesn't remove it from all tabs --- packages/solid-query/src/useBaseQuery.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/solid-query/src/useBaseQuery.ts b/packages/solid-query/src/useBaseQuery.ts index c77c6afa56..0b504ed0a7 100644 --- a/packages/solid-query/src/useBaseQuery.ts +++ b/packages/solid-query/src/useBaseQuery.ts @@ -117,7 +117,6 @@ export function useBaseQuery< type ResourceData = QueryObserverResult const client = createMemo(() => useQueryClient(queryClient?.())) - const isRestoring = useIsRestoring() // There are times when we run a query on the server but the resource is never read // This could lead to times when the queryObserver is unsubscribed before the resource has loaded From 35a24ee4569c7cfc2ce3da209e1a69167492a27c Mon Sep 17 00:00:00 2001 From: gopnik5 Date: Thu, 24 Apr 2025 15:37:40 -0400 Subject: [PATCH 4/4] isolated tests --- .../src/__tests__/index.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/query-broadcast-client-experimental/src/__tests__/index.test.ts b/packages/query-broadcast-client-experimental/src/__tests__/index.test.ts index 14686ac97b..763a7edd58 100644 --- a/packages/query-broadcast-client-experimental/src/__tests__/index.test.ts +++ b/packages/query-broadcast-client-experimental/src/__tests__/index.test.ts @@ -6,7 +6,6 @@ import type { QueryCache } from '@tanstack/query-core' describe('broadcastQueryClient', () => { let queryClient: QueryClient let queryCache: QueryCache - let unsubscribe: () => void beforeEach(() => { queryClient = new QueryClient() @@ -14,7 +13,7 @@ describe('broadcastQueryClient', () => { }) it('should subscribe to the query cache', async () => { - unsubscribe = broadcastQueryClient({ + broadcastQueryClient({ queryClient, broadcastChannel: 'test_channel', }) @@ -22,6 +21,10 @@ describe('broadcastQueryClient', () => { }) it('should not have any listeners after cleanup', async () => { + const unsubscribe = broadcastQueryClient({ + queryClient, + broadcastChannel: 'test_channel', + }) unsubscribe() expect(queryCache.hasListeners()).toBe(false) })