From f86eb7e099af48b9b9ee0412431180fe90148c8a Mon Sep 17 00:00:00 2001 From: Dominik Dorfmeister Date: Fri, 31 Jan 2025 10:02:56 +0100 Subject: [PATCH] feat(core): add client to queryFunctionContext (#8599) * feat: add queryClient to queryFunctionContext * fix: remove queryClient exception closing over a queryClient should now error, as we pass the queryClient directly to the queryFunctionContext * fix: persister * refactor: keep private reference to cache * chore: fix tests * docs: QueryFunctionContext * refactor: derive from private member * refactor: name it `client` * refactor: let's go with client * chore: try skipping the cache * chore: re-enable caching and try to bust it by changing sharedGlobals lol --- .../framework/react/guides/query-functions.md | 1 + nx.json | 2 +- .../src/__tests__/inject-query.test.ts | 1 + .../src/__tests__/exhaustive-deps.test.ts | 20 +------------------ .../exhaustive-deps/exhaustive-deps.utils.ts | 13 +----------- .../__tests__/infiniteQueryBehavior.test.tsx | 9 +++++++++ .../query-core/src/__tests__/query.test.tsx | 1 + .../src/__tests__/queryClient.test-d.tsx | 1 + .../query-core/src/infiniteQueryBehavior.ts | 2 ++ packages/query-core/src/query.ts | 12 ++++++++--- packages/query-core/src/queryCache.ts | 2 +- packages/query-core/src/types.ts | 3 +++ .../src/__tests__/createPersister.test.ts | 10 ++++++---- 13 files changed, 37 insertions(+), 40 deletions(-) diff --git a/docs/framework/react/guides/query-functions.md b/docs/framework/react/guides/query-functions.md index 92faed581e..4b3cffe871 100644 --- a/docs/framework/react/guides/query-functions.md +++ b/docs/framework/react/guides/query-functions.md @@ -100,6 +100,7 @@ function fetchTodoList({ queryKey }) { The `QueryFunctionContext` is the object passed to each query function. It consists of: - `queryKey: QueryKey`: [Query Keys](../query-keys) +- `client: QueryClient`: [QueryClient](../../../../reference/QueryClient) - `signal?: AbortSignal` - [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) instance provided by TanStack Query - Can be used for [Query Cancellation](../query-cancellation) diff --git a/nx.json b/nx.json index 8c9326f64b..e13db2432d 100644 --- a/nx.json +++ b/nx.json @@ -8,7 +8,7 @@ "sharedGlobals": [ "{workspaceRoot}/.nvmrc", "{workspaceRoot}/package.json", - "{workspaceRoot}/scripts/getTsupConfig.js", + "{workspaceRoot}/scripts/*.js", "{workspaceRoot}/tsconfig.json", "{workspaceRoot}/eslint.config.js" ], diff --git a/packages/angular-query-experimental/src/__tests__/inject-query.test.ts b/packages/angular-query-experimental/src/__tests__/inject-query.test.ts index a70d59e8c2..68913f1a76 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-query.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-query.test.ts @@ -325,6 +325,7 @@ describe('injectQuery', () => { expect(spy).toHaveBeenCalledTimes(2) // should call queryFn with context containing the new queryKey expect(spy).toBeCalledWith({ + client: queryClient, meta: undefined, queryKey: ['key8'], signal: expect.anything(), diff --git a/packages/eslint-plugin-query/src/__tests__/exhaustive-deps.test.ts b/packages/eslint-plugin-query/src/__tests__/exhaustive-deps.test.ts index 255313ae3e..e3ea5790dd 100644 --- a/packages/eslint-plugin-query/src/__tests__/exhaustive-deps.test.ts +++ b/packages/eslint-plugin-query/src/__tests__/exhaustive-deps.test.ts @@ -354,24 +354,6 @@ ruleTester.run('exhaustive-deps', rule, { } `, }, - { - name: 'should ignore references of the queryClient', - code: ` - const CONST_VAL = 1 - function useHook() { - const queryClient = useQueryClient() - const queryClient2 = useQueryClient() - useQuery({ - queryKey: ["foo"], - queryFn: () => { - doSomething(queryClient) - queryClient.invalidateQueries() - doSomethingSus(queryClient2) - } - }); - } - `, - }, { name: 'query key with nullish coalescing operator', code: ` @@ -470,7 +452,7 @@ ruleTester.run('exhaustive-deps', rule, { queryKey: ['foo'], queryFn: () => Promise.resolve(EXTERNAL), }), - }; + }; `, }, { diff --git a/packages/eslint-plugin-query/src/rules/exhaustive-deps/exhaustive-deps.utils.ts b/packages/eslint-plugin-query/src/rules/exhaustive-deps/exhaustive-deps.utils.ts index 5c45d1d0e8..5762f506d1 100644 --- a/packages/eslint-plugin-query/src/rules/exhaustive-deps/exhaustive-deps.utils.ts +++ b/packages/eslint-plugin-query/src/rules/exhaustive-deps/exhaustive-deps.utils.ts @@ -29,8 +29,7 @@ export const ExhaustiveDepsUtils = { return ( reference.identifier.name !== 'undefined' && reference.identifier.parent.type !== AST_NODE_TYPES.NewExpression && - !ExhaustiveDepsUtils.isInstanceOfKind(reference.identifier.parent) && - !ExhaustiveDepsUtils.isQueryClientReference(reference) + !ExhaustiveDepsUtils.isInstanceOfKind(reference.identifier.parent) ) }, isInstanceOfKind(node: TSESTree.Node) { @@ -39,14 +38,4 @@ export const ExhaustiveDepsUtils = { node.operator === 'instanceof' ) }, - isQueryClientReference(reference: TSESLint.Scope.Reference) { - const declarator = reference.resolved?.defs[0]?.node - - return ( - declarator?.type === AST_NODE_TYPES.VariableDeclarator && - declarator.init?.type === AST_NODE_TYPES.CallExpression && - declarator.init.callee.type === AST_NODE_TYPES.Identifier && - declarator.init.callee.name === 'useQueryClient' - ) - }, } diff --git a/packages/query-core/src/__tests__/infiniteQueryBehavior.test.tsx b/packages/query-core/src/__tests__/infiniteQueryBehavior.test.tsx index b1bed76286..8862b368a4 100644 --- a/packages/query-core/src/__tests__/infiniteQueryBehavior.test.tsx +++ b/packages/query-core/src/__tests__/infiniteQueryBehavior.test.tsx @@ -88,6 +88,7 @@ describe('InfiniteQueryBehavior', () => { expect(queryFnSpy).toHaveBeenNthCalledWith(1, { queryKey: key, + client: queryClient, pageParam: 1, meta: undefined, direction: 'forward', @@ -101,6 +102,7 @@ describe('InfiniteQueryBehavior', () => { expect(queryFnSpy).toHaveBeenNthCalledWith(1, { queryKey: key, + client: queryClient, pageParam: 2, direction: 'forward', meta: undefined, @@ -119,6 +121,7 @@ describe('InfiniteQueryBehavior', () => { expect(queryFnSpy).toHaveBeenNthCalledWith(1, { queryKey: key, + client: queryClient, pageParam: 0, direction: 'backward', meta: undefined, @@ -138,6 +141,7 @@ describe('InfiniteQueryBehavior', () => { expect(queryFnSpy).toHaveBeenNthCalledWith(1, { queryKey: key, + client: queryClient, pageParam: -1, meta: undefined, direction: 'backward', @@ -156,6 +160,7 @@ describe('InfiniteQueryBehavior', () => { expect(queryFnSpy).toHaveBeenNthCalledWith(1, { queryKey: key, + client: queryClient, pageParam: 1, meta: undefined, direction: 'forward', @@ -177,6 +182,7 @@ describe('InfiniteQueryBehavior', () => { expect(queryFnSpy).toHaveBeenNthCalledWith(1, { queryKey: key, + client: queryClient, pageParam: 0, meta: undefined, direction: 'forward', @@ -185,6 +191,7 @@ describe('InfiniteQueryBehavior', () => { expect(queryFnSpy).toHaveBeenNthCalledWith(2, { queryKey: key, + client: queryClient, pageParam: 1, meta: undefined, direction: 'forward', @@ -237,6 +244,7 @@ describe('InfiniteQueryBehavior', () => { expect(queryFnSpy).toHaveBeenNthCalledWith(1, { queryKey: key, + client: queryClient, pageParam: 1, meta: undefined, direction: 'forward', @@ -293,6 +301,7 @@ describe('InfiniteQueryBehavior', () => { expect(queryFnSpy).toHaveBeenNthCalledWith(1, { queryKey: key, + client: queryClient, pageParam: 2, meta: undefined, direction: 'forward', diff --git a/packages/query-core/src/__tests__/query.test.tsx b/packages/query-core/src/__tests__/query.test.tsx index 6f7ef6f058..ea23037f10 100644 --- a/packages/query-core/src/__tests__/query.test.tsx +++ b/packages/query-core/src/__tests__/query.test.tsx @@ -214,6 +214,7 @@ describe('query', () => { expect(args.pageParam).toBeUndefined() expect(args.queryKey).toEqual(key) expect(args.signal).toBeInstanceOf(AbortSignal) + expect(args.client).toEqual(queryClient) }) test('should continue if cancellation is not supported and signal is not consumed', async () => { diff --git a/packages/query-core/src/__tests__/queryClient.test-d.tsx b/packages/query-core/src/__tests__/queryClient.test-d.tsx index ddde0903ad..04a8f26a37 100644 --- a/packages/query-core/src/__tests__/queryClient.test-d.tsx +++ b/packages/query-core/src/__tests__/queryClient.test-d.tsx @@ -184,6 +184,7 @@ describe('defaultOptions', () => { queries: { queryFn: (context) => { expectTypeOf(context).toEqualTypeOf<{ + client: QueryClient queryKey: QueryKey meta: Record | undefined signal: AbortSignal diff --git a/packages/query-core/src/infiniteQueryBehavior.ts b/packages/query-core/src/infiniteQueryBehavior.ts index 9dc28f230e..9cb616da27 100644 --- a/packages/query-core/src/infiniteQueryBehavior.ts +++ b/packages/query-core/src/infiniteQueryBehavior.ts @@ -58,6 +58,7 @@ export function infiniteQueryBehavior( QueryFunctionContext, 'signal' > = { + client: context.client, queryKey: context.queryKey, pageParam: param, direction: previous ? 'backward' : 'forward', @@ -114,6 +115,7 @@ export function infiniteQueryBehavior( return context.options.persister?.( fetchFn as any, { + client: context.client, queryKey: context.queryKey, meta: context.options.meta, signal: context.signal, diff --git a/packages/query-core/src/query.ts b/packages/query-core/src/query.ts index 3485d8ce28..e6ad4ca4ee 100644 --- a/packages/query-core/src/query.ts +++ b/packages/query-core/src/query.ts @@ -9,6 +9,8 @@ import { import { notifyManager } from './notifyManager' import { canFetch, createRetryer, isCancelledError } from './retryer' import { Removable } from './removable' +import type { QueryCache } from './queryCache' +import type { QueryClient } from './queryClient' import type { CancelOptions, DefaultError, @@ -23,7 +25,6 @@ import type { QueryStatus, SetDataOptions, } from './types' -import type { QueryCache } from './queryCache' import type { QueryObserver } from './queryObserver' import type { Retryer } from './retryer' @@ -35,7 +36,7 @@ interface QueryConfig< TData, TQueryKey extends QueryKey = QueryKey, > { - cache: QueryCache + client: QueryClient queryKey: TQueryKey queryHash: string options?: QueryOptions @@ -68,6 +69,7 @@ export interface FetchContext< fetchOptions?: FetchOptions signal: AbortSignal options: QueryOptions + client: QueryClient queryKey: TQueryKey state: QueryState } @@ -167,6 +169,7 @@ export class Query< #initialState: QueryState #revertState?: QueryState #cache: QueryCache + #client: QueryClient #retryer?: Retryer observers: Array> #defaultOptions?: QueryOptions @@ -179,7 +182,8 @@ export class Query< this.#defaultOptions = config.defaultOptions this.setOptions(config.options) this.observers = [] - this.#cache = config.cache + this.#client = config.client + this.#cache = this.#client.getQueryCache() this.queryKey = config.queryKey this.queryHash = config.queryHash this.#initialState = getDefaultState(this.options) @@ -411,6 +415,7 @@ export class Query< QueryFunctionContext, 'signal' > = { + client: this.#client, queryKey: this.queryKey, meta: this.meta, } @@ -437,6 +442,7 @@ export class Query< fetchOptions, options: this.options, queryKey: this.queryKey, + client: this.#client, state: this.state, fetchFn, } diff --git a/packages/query-core/src/queryCache.ts b/packages/query-core/src/queryCache.ts index 8f637e0a39..3c597610bc 100644 --- a/packages/query-core/src/queryCache.ts +++ b/packages/query-core/src/queryCache.ts @@ -117,7 +117,7 @@ export class QueryCache extends Subscribable { if (!query) { query = new Query({ - cache: this, + client, queryKey, queryHash, options: client.defaultQueryOptions(options), diff --git a/packages/query-core/src/types.ts b/packages/query-core/src/types.ts index 2767aec1c1..6d94daabc0 100644 --- a/packages/query-core/src/types.ts +++ b/packages/query-core/src/types.ts @@ -1,5 +1,6 @@ /* istanbul ignore file */ +import type { QueryClient } from './queryClient' import type { DehydrateOptions, HydrateOptions } from './hydration' import type { MutationState } from './mutation' import type { FetchDirection, Query, QueryBehavior } from './query' @@ -116,6 +117,7 @@ export type QueryFunctionContext< TPageParam = never, > = [TPageParam] extends [never] ? { + client: QueryClient queryKey: TQueryKey signal: AbortSignal meta: QueryMeta | undefined @@ -127,6 +129,7 @@ export type QueryFunctionContext< direction?: unknown } : { + client: QueryClient queryKey: TQueryKey signal: AbortSignal pageParam: TPageParam diff --git a/packages/query-persist-client-core/src/__tests__/createPersister.test.ts b/packages/query-persist-client-core/src/__tests__/createPersister.test.ts index 9aece2fcd2..1c8f5b6ef8 100644 --- a/packages/query-persist-client-core/src/__tests__/createPersister.test.ts +++ b/packages/query-persist-client-core/src/__tests__/createPersister.test.ts @@ -1,12 +1,12 @@ import { describe, expect, test, vi } from 'vitest' -import { Query, QueryCache, hashKey } from '@tanstack/query-core' +import { Query, QueryClient, hashKey } from '@tanstack/query-core' import { PERSISTER_KEY_PREFIX, experimental_createPersister, } from '../createPersister' import { sleep } from './utils' +import type { QueryFunctionContext, QueryKey } from '@tanstack/query-core' import type { StoragePersisterOptions } from '../createPersister' -import type { QueryKey } from '@tanstack/query-core' function getFreshStorage() { const storage = new Map() @@ -25,12 +25,14 @@ function setupPersister( queryKey: QueryKey, persisterOptions: StoragePersisterOptions, ) { + const client = new QueryClient() const context = { meta: { foo: 'bar' }, + client, queryKey, // @ts-expect-error signal: undefined as AbortSignal, - } + } satisfies QueryFunctionContext const queryHash = hashKey(queryKey) const storageKey = `${PERSISTER_KEY_PREFIX}-${queryHash}` @@ -39,7 +41,7 @@ function setupPersister( const persisterFn = experimental_createPersister(persisterOptions) const query = new Query({ - cache: new QueryCache(), + client, queryHash, queryKey, })