From bec6274bab9dbb618d3ee5890dfe6acfb5527b02 Mon Sep 17 00:00:00 2001 From: EskiMojo14 Date: Sat, 27 Jan 2024 19:00:56 +0000 Subject: [PATCH 1/9] add version of reactHooksModule which only builds hooks when a method is called --- packages/toolkit/src/query/react/index.ts | 17 ++- packages/toolkit/src/query/react/module.ts | 130 ++++++++++++++++-- .../src/query/tests/lazyReactHooks.test.tsx | 61 ++++++++ 3 files changed, 197 insertions(+), 11 deletions(-) create mode 100644 packages/toolkit/src/query/tests/lazyReactHooks.test.tsx diff --git a/packages/toolkit/src/query/react/index.ts b/packages/toolkit/src/query/react/index.ts index 437fc4287c..b49249a713 100644 --- a/packages/toolkit/src/query/react/index.ts +++ b/packages/toolkit/src/query/react/index.ts @@ -3,14 +3,19 @@ import { formatProdErrorMessage } from '@reduxjs/toolkit' import { buildCreateApi, coreModule } from '@reduxjs/toolkit/query' -import { reactHooksModule, reactHooksModuleName } from './module' +import { + reactHooksModule, + reactHooksModuleName, + lazyReactHooksModule, + lazyReactHooksModuleName, +} from './module' export * from '@reduxjs/toolkit/query' export { ApiProvider } from './ApiProvider' const createApi = /* @__PURE__ */ buildCreateApi( coreModule(), - reactHooksModule() + reactHooksModule(), ) export type { @@ -19,4 +24,10 @@ export type { TypedUseQueryStateResult, TypedUseQuerySubscriptionResult, } from './buildHooks' -export { createApi, reactHooksModule, reactHooksModuleName } +export { + createApi, + reactHooksModule, + reactHooksModuleName, + lazyReactHooksModule, + lazyReactHooksModuleName, +} diff --git a/packages/toolkit/src/query/react/module.ts b/packages/toolkit/src/query/react/module.ts index 68bcddb253..f08e83d5e5 100644 --- a/packages/toolkit/src/query/react/module.ts +++ b/packages/toolkit/src/query/react/module.ts @@ -25,10 +25,14 @@ import { createSelector as _createSelector } from 'reselect' import type { QueryKeys } from '../core/apiState' import type { PrefetchOptions } from '../core/module' import { countObjectKeys } from '../utils/countObjectKeys' +import { delay } from 'msw' export const reactHooksModuleName = /* @__PURE__ */ Symbol() export type ReactHooksModule = typeof reactHooksModuleName +export const lazyReactHooksModuleName = /* @__PURE__ */ Symbol() +export type LazyReactHooksModule = typeof lazyReactHooksModuleName + declare module '@reduxjs/toolkit/query' { export interface ApiModules< // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -37,8 +41,36 @@ declare module '@reduxjs/toolkit/query' { // eslint-disable-next-line @typescript-eslint/no-unused-vars ReducerPath extends string, // eslint-disable-next-line @typescript-eslint/no-unused-vars - TagTypes extends string + TagTypes extends string, > { + [lazyReactHooksModuleName]: { + buildHooks(): { + endpoints: { + [K in keyof Definitions]: Definitions[K] extends QueryDefinition< + any, + any, + any, + any, + any + > + ? QueryHooks + : Definitions[K] extends MutationDefinition + ? MutationHooks + : never + } + + /** + * A hook that accepts a string endpoint name, and provides a callback that when called, pre-fetches the data for that endpoint. + */ + usePrefetch>( + endpointName: EndpointName, + options?: PrefetchOptions, + ): ( + arg: QueryArgFrom, + options?: PrefetchOptions, + ) => void + } & HooksWithUniqueNames + } [reactHooksModuleName]: { /** * Endpoints based on the input endpoints provided to `createApi`, containing `select`, `hooks` and `action matchers`. @@ -53,18 +85,18 @@ declare module '@reduxjs/toolkit/query' { > ? QueryHooks : Definitions[K] extends MutationDefinition - ? MutationHooks - : never + ? MutationHooks + : never } /** * A hook that accepts a string endpoint name, and provides a callback that when called, pre-fetches the data for that endpoint. */ usePrefetch>( endpointName: EndpointName, - options?: PrefetchOptions + options?: PrefetchOptions, ): ( arg: QueryArgFrom, - options?: PrefetchOptions + options?: PrefetchOptions, ) => void } & HooksWithUniqueNames } @@ -160,7 +192,7 @@ export const reactHooksModule = ({ if (!warned) { console.warn( 'As of RTK 2.0, the hooks now need to be specified as one object, provided under a `hooks` key:' + - '\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`' + '\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`', ) warned = true } @@ -175,8 +207,8 @@ export const reactHooksModule = ({ `When using custom hooks for context, all ${ hookNames.length } hooks need to be provided: ${hookNames.join( - ', ' - )}.\nHook ${hookName} was either not provided or not a function.` + ', ', + )}.\nHook ${hookName} was either not provided or not a function.`, ) } } @@ -203,6 +235,7 @@ export const reactHooksModule = ({ serializeQueryArgs, context, }) + safeAssign(anyApi, { usePrefetch }) safeAssign(context, { batch }) @@ -239,3 +272,84 @@ export const reactHooksModule = ({ }, } } + +export const lazyReactHooksModule = ({ + batch = rrBatch, + hooks = { + useDispatch: rrUseDispatch, + useSelector: rrUseSelector, + useStore: rrUseStore, + }, + createSelector = _createSelector, + unstable__sideEffectsInRender = false, +}: ReactHooksModuleOptions = {}): Module => ({ + name: lazyReactHooksModuleName, + init(api, { serializeQueryArgs }, context) { + const anyApi = api as any as Api< + any, + Record, + any, + any, + LazyReactHooksModule + > + + function buildEndpointHooks() { + const { buildQueryHooks, buildMutationHook, usePrefetch } = buildHooks({ + api, + moduleOptions: { + batch, + hooks, + unstable__sideEffectsInRender, + createSelector, + }, + serializeQueryArgs, + context, + }) + + const result: { + endpoints: Record | MutationHooks> + usePrefetch: typeof usePrefetch + } = { + endpoints: {}, + usePrefetch, + } + for (const [endpointName, definition] of Object.entries( + context.endpointDefinitions, + )) { + if (isQueryDefinition(definition)) { + const { + useQuery, + useLazyQuery, + useLazyQuerySubscription, + useQueryState, + useQuerySubscription, + } = buildQueryHooks(endpointName) + result.endpoints[endpointName] = { + useQuery, + useLazyQuery, + useLazyQuerySubscription, + useQueryState, + useQuerySubscription, + } + ;(result as any)[`use${capitalize(endpointName)}Query`] = useQuery + ;(result as any)[`useLazy${capitalize(endpointName)}Query`] = + useLazyQuery + } else if (isMutationDefinition(definition)) { + const useMutation = buildMutationHook(endpointName) + result.endpoints[endpointName] = { useMutation } + ;(result as any)[`use${capitalize(endpointName)}Mutation`] = + useMutation + } else { + throw new Error(`Invalid endpoint definition for ${endpointName}`) + } + } + return result + } + + safeAssign(anyApi, { buildHooks: buildEndpointHooks }) + + return { + injectEndpoint() {}, + } + }, +}) diff --git a/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx b/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx new file mode 100644 index 0000000000..269193420c --- /dev/null +++ b/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx @@ -0,0 +1,61 @@ +import { delay } from 'msw' +import { coreModule } from '../core' +import { buildCreateApi } from '../createApi' +import { fakeBaseQuery, lazyReactHooksModule } from '../react' + +const createApi = buildCreateApi(coreModule(), lazyReactHooksModule()) + +interface Post { + id: number + title: string +} + +const api = createApi({ + baseQuery: fakeBaseQuery(), + endpoints: (build) => ({ + getPost: build.query({ + async queryFn(id) { + await delay() + return { + data: { + id, + title: 'foo', + }, + } + }, + }), + deletePost: build.mutation({ + async queryFn() { + await delay() + return { + data: undefined, + } + }, + }), + }), +}) +describe('lazy react hooks', () => { + it('only creates hooks once buildHooks is called', async () => { + expect(api.endpoints.getPost).not.toHaveProperty('useQuery') + expect(api).not.toHaveProperty('useGetPostQuery') + + expect(api.endpoints.deletePost).not.toHaveProperty('useMutation') + expect(api).not.toHaveProperty('useDeletePostMutation') + + const hooks = api.buildHooks() + + expect(hooks.endpoints.getPost).toEqual({ + useLazyQuery: expect.any(Function), + useLazyQuerySubscription: expect.any(Function), + useQuery: expect.any(Function), + useQueryState: expect.any(Function), + useQuerySubscription: expect.any(Function), + }) + expect(hooks.useGetPostQuery).toEqual(expect.any(Function)) + + expect(hooks.endpoints.deletePost).toEqual({ + useMutation: expect.any(Function), + }) + expect(hooks.useDeletePostMutation).toEqual(expect.any(Function)) + }) +}) From 01fb4dc5f72ab65e2251a300188c93dc8d34af42 Mon Sep 17 00:00:00 2001 From: EskiMojo14 Date: Sat, 27 Jan 2024 19:03:32 +0000 Subject: [PATCH 2/9] unused import --- packages/toolkit/src/query/react/module.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/toolkit/src/query/react/module.ts b/packages/toolkit/src/query/react/module.ts index f08e83d5e5..bb82e18af5 100644 --- a/packages/toolkit/src/query/react/module.ts +++ b/packages/toolkit/src/query/react/module.ts @@ -25,7 +25,6 @@ import { createSelector as _createSelector } from 'reselect' import type { QueryKeys } from '../core/apiState' import type { PrefetchOptions } from '../core/module' import { countObjectKeys } from '../utils/countObjectKeys' -import { delay } from 'msw' export const reactHooksModuleName = /* @__PURE__ */ Symbol() export type ReactHooksModule = typeof reactHooksModuleName From 7facba8d7814575d832aa4738834ff69ef5800f6 Mon Sep 17 00:00:00 2001 From: EskiMojo14 Date: Sat, 27 Jan 2024 19:16:57 +0000 Subject: [PATCH 3/9] make it DRY --- packages/toolkit/src/query/react/module.ts | 138 +++++++++------------ 1 file changed, 58 insertions(+), 80 deletions(-) diff --git a/packages/toolkit/src/query/react/module.ts b/packages/toolkit/src/query/react/module.ts index bb82e18af5..2b0d5efe5a 100644 --- a/packages/toolkit/src/query/react/module.ts +++ b/packages/toolkit/src/query/react/module.ts @@ -1,5 +1,6 @@ import type { Api, + ApiModules, BaseQueryFn, EndpointDefinitions, Module, @@ -25,6 +26,7 @@ import { createSelector as _createSelector } from 'reselect' import type { QueryKeys } from '../core/apiState' import type { PrefetchOptions } from '../core/module' import { countObjectKeys } from '../utils/countObjectKeys' +import { t } from 'vitest/dist/reporters-qc5Smpt5' export const reactHooksModuleName = /* @__PURE__ */ Symbol() export type ReactHooksModule = typeof reactHooksModuleName @@ -43,32 +45,12 @@ declare module '@reduxjs/toolkit/query' { TagTypes extends string, > { [lazyReactHooksModuleName]: { - buildHooks(): { - endpoints: { - [K in keyof Definitions]: Definitions[K] extends QueryDefinition< - any, - any, - any, - any, - any - > - ? QueryHooks - : Definitions[K] extends MutationDefinition - ? MutationHooks - : never - } - - /** - * A hook that accepts a string endpoint name, and provides a callback that when called, pre-fetches the data for that endpoint. - */ - usePrefetch>( - endpointName: EndpointName, - options?: PrefetchOptions, - ): ( - arg: QueryArgFrom, - options?: PrefetchOptions, - ) => void - } & HooksWithUniqueNames + buildHooks(): ApiModules< + BaseQuery, + Definitions, + ReducerPath, + TagTypes + >[ReactHooksModule] } [reactHooksModuleName]: { /** @@ -150,6 +132,44 @@ export interface ReactHooksModuleOptions { createSelector?: typeof _createSelector } +function buildInjectEndpoint( + target: ApiModules, any, any>[ReactHooksModule], + { + buildMutationHook, + buildQueryHooks, + }: Pick< + ReturnType, + 'buildQueryHooks' | 'buildMutationHook' + >, +): ReturnType['init']>['injectEndpoint'] { + return function injectEndpoint(endpointName, definition) { + if (isQueryDefinition(definition)) { + const { + useQuery, + useLazyQuery, + useLazyQuerySubscription, + useQueryState, + useQuerySubscription, + } = buildQueryHooks(endpointName) + safeAssign(target.endpoints[endpointName], { + useQuery, + useLazyQuery, + useLazyQuerySubscription, + useQueryState, + useQuerySubscription, + }) + ;(target as any)[`use${capitalize(endpointName)}Query`] = useQuery + ;(target as any)[`useLazy${capitalize(endpointName)}Query`] = useLazyQuery + } else if (isMutationDefinition(definition)) { + const useMutation = buildMutationHook(endpointName) + safeAssign(target.endpoints[endpointName], { + useMutation, + }) + ;(target as any)[`use${capitalize(endpointName)}Mutation`] = useMutation + } + } +} + /** * Creates a module that generates react hooks from endpoints, for use with `buildCreateApi`. * @@ -239,34 +259,10 @@ export const reactHooksModule = ({ safeAssign(context, { batch }) return { - injectEndpoint(endpointName, definition) { - if (isQueryDefinition(definition)) { - const { - useQuery, - useLazyQuery, - useLazyQuerySubscription, - useQueryState, - useQuerySubscription, - } = buildQueryHooks(endpointName) - safeAssign(anyApi.endpoints[endpointName], { - useQuery, - useLazyQuery, - useLazyQuerySubscription, - useQueryState, - useQuerySubscription, - }) - ;(api as any)[`use${capitalize(endpointName)}Query`] = useQuery - ;(api as any)[`useLazy${capitalize(endpointName)}Query`] = - useLazyQuery - } else if (isMutationDefinition(definition)) { - const useMutation = buildMutationHook(endpointName) - safeAssign(anyApi.endpoints[endpointName], { - useMutation, - }) - ;(api as any)[`use${capitalize(endpointName)}Mutation`] = - useMutation - } - }, + injectEndpoint: buildInjectEndpoint(anyApi, { + buildMutationHook, + buildQueryHooks, + }), } }, } @@ -312,35 +308,17 @@ export const lazyReactHooksModule = ({ endpoints: {}, usePrefetch, } + + const injectEndpoint = buildInjectEndpoint(result, { + buildMutationHook, + buildQueryHooks, + }) + for (const [endpointName, definition] of Object.entries( context.endpointDefinitions, )) { - if (isQueryDefinition(definition)) { - const { - useQuery, - useLazyQuery, - useLazyQuerySubscription, - useQueryState, - useQuerySubscription, - } = buildQueryHooks(endpointName) - result.endpoints[endpointName] = { - useQuery, - useLazyQuery, - useLazyQuerySubscription, - useQueryState, - useQuerySubscription, - } - ;(result as any)[`use${capitalize(endpointName)}Query`] = useQuery - ;(result as any)[`useLazy${capitalize(endpointName)}Query`] = - useLazyQuery - } else if (isMutationDefinition(definition)) { - const useMutation = buildMutationHook(endpointName) - result.endpoints[endpointName] = { useMutation } - ;(result as any)[`use${capitalize(endpointName)}Mutation`] = - useMutation - } else { - throw new Error(`Invalid endpoint definition for ${endpointName}`) - } + result.endpoints[endpointName] = {} as any + injectEndpoint(endpointName, definition) } return result } From 0352f3484fa1f3943487e09e6b3de3896be6b94e Mon Sep 17 00:00:00 2001 From: EskiMojo14 Date: Sat, 27 Jan 2024 19:22:24 +0000 Subject: [PATCH 4/9] allow providing options when calling buildHooks --- packages/toolkit/src/query/react/module.ts | 56 +++++++++++++--------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/packages/toolkit/src/query/react/module.ts b/packages/toolkit/src/query/react/module.ts index 2b0d5efe5a..7b2ba19b23 100644 --- a/packages/toolkit/src/query/react/module.ts +++ b/packages/toolkit/src/query/react/module.ts @@ -45,7 +45,9 @@ declare module '@reduxjs/toolkit/query' { TagTypes extends string, > { [lazyReactHooksModuleName]: { - buildHooks(): ApiModules< + buildHooks( + options?: ReactHooksModuleOptions, + ): ApiModules< BaseQuery, Definitions, ReducerPath, @@ -170,6 +172,17 @@ function buildInjectEndpoint( } } +const defaultOptions: Required = { + batch: rrBatch, + hooks: { + useDispatch: rrUseDispatch, + useSelector: rrUseSelector, + useStore: rrUseStore, + }, + createSelector: _createSelector, + unstable__sideEffectsInRender: false, +} + /** * Creates a module that generates react hooks from endpoints, for use with `buildCreateApi`. * @@ -190,17 +203,16 @@ function buildInjectEndpoint( * * @returns A module for use with `buildCreateApi` */ -export const reactHooksModule = ({ - batch = rrBatch, - hooks = { - useDispatch: rrUseDispatch, - useSelector: rrUseSelector, - useStore: rrUseStore, - }, - createSelector = _createSelector, - unstable__sideEffectsInRender = false, - ...rest -}: ReactHooksModuleOptions = {}): Module => { +export const reactHooksModule = ( + moduleOptions?: ReactHooksModuleOptions, +): Module => { + const { + batch, + hooks, + createSelector, + unstable__sideEffectsInRender, + ...rest + } = { ...defaultOptions, ...moduleOptions } if (process.env.NODE_ENV !== 'production') { const hookNames = ['useDispatch', 'useSelector', 'useStore'] as const let warned = false @@ -268,16 +280,9 @@ export const reactHooksModule = ({ } } -export const lazyReactHooksModule = ({ - batch = rrBatch, - hooks = { - useDispatch: rrUseDispatch, - useSelector: rrUseSelector, - useStore: rrUseStore, - }, - createSelector = _createSelector, - unstable__sideEffectsInRender = false, -}: ReactHooksModuleOptions = {}): Module => ({ +export const lazyReactHooksModule = ( + moduleOptions?: ReactHooksModuleOptions, +): Module => ({ name: lazyReactHooksModuleName, init(api, { serializeQueryArgs }, context) { const anyApi = api as any as Api< @@ -288,7 +293,12 @@ export const lazyReactHooksModule = ({ LazyReactHooksModule > - function buildEndpointHooks() { + function buildEndpointHooks(options?: ReactHooksModuleOptions) { + const { batch, hooks, unstable__sideEffectsInRender, createSelector } = { + ...defaultOptions, + ...moduleOptions, + ...options, + } const { buildQueryHooks, buildMutationHook, usePrefetch } = buildHooks({ api, moduleOptions: { From 389d5bc86bad1d34d2d189188a0821c173beb27b Mon Sep 17 00:00:00 2001 From: EskiMojo14 Date: Sat, 27 Jan 2024 19:36:23 +0000 Subject: [PATCH 5/9] try something --- packages/toolkit/src/query/createApi.ts | 36 ++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/toolkit/src/query/createApi.ts b/packages/toolkit/src/query/createApi.ts index ed22f4ec9e..0159588f1d 100644 --- a/packages/toolkit/src/query/createApi.ts +++ b/packages/toolkit/src/query/createApi.ts @@ -17,7 +17,7 @@ export interface CreateApiOptions< BaseQuery extends BaseQueryFn, Definitions extends EndpointDefinitions, ReducerPath extends string = 'api', - TagTypes extends string = never + TagTypes extends string = never, > { /** * The base query used by each endpoint if no `queryFn` option is specified. RTK Query exports a utility called [fetchBaseQuery](./fetchBaseQuery) as a lightweight wrapper around `fetch` for common use-cases. See [Customizing Queries](../../rtk-query/usage/customizing-queries) if `fetchBaseQuery` does not handle your requirements. @@ -97,7 +97,7 @@ export interface CreateApiOptions< * Endpoints are just a set of operations that you want to perform against your server. You define them as an object using the builder syntax. There are two basic endpoint types: [`query`](../../rtk-query/usage/queries) and [`mutation`](../../rtk-query/usage/mutations). */ endpoints( - build: EndpointBuilder + build: EndpointBuilder, ): Definitions /** * Defaults to `60` _(this value is in seconds)_. This is how long RTK Query will keep your data cached for **after** the last component unsubscribes. For example, if you query an endpoint, then unmount the component, then mount another component that makes the same request within the given time frame, the most recent value will be served from the cache. @@ -200,7 +200,7 @@ export interface CreateApiOptions< reducerPath, }: { reducerPath: ReducerPath - } + }, ) => | undefined | CombinedState< @@ -220,9 +220,9 @@ export type CreateApi = { BaseQuery extends BaseQueryFn, Definitions extends EndpointDefinitions, ReducerPath extends string = 'api', - TagTypes extends string = never + TagTypes extends string = never, >( - options: CreateApiOptions + options: CreateApiOptions, ): Api } @@ -249,14 +249,14 @@ export type CreateApi = { * @param modules - A variable number of modules that customize how the `createApi` method handles endpoints * @returns A `createApi` method using the provided `modules`. */ -export function buildCreateApi, ...Module[]]>( - ...modules: Modules -): CreateApi { +export function buildCreateApi( + ...modules: [...{ [K in keyof Modules]: Module }] +): CreateApi { return function baseCreateApi(options) { const extractRehydrationInfo = weakMapMemoize((action: UnknownAction) => options.extractRehydrationInfo?.(action, { reducerPath: (options.reducerPath ?? 'api') as any, - }) + }), ) const optionsWithDefaults: CreateApiOptions = { @@ -305,7 +305,7 @@ export function buildCreateApi, ...Module[]]>( apiUid: nanoid(), extractRehydrationInfo, hasRehydrationInfo: weakMapMemoize( - (action) => extractRehydrationInfo(action) != null + (action) => extractRehydrationInfo(action) != null, ), } @@ -321,14 +321,14 @@ export function buildCreateApi, ...Module[]]>( } if (endpoints) { for (const [endpointName, partialDefinition] of Object.entries( - endpoints + endpoints, )) { if (typeof partialDefinition === 'function') { partialDefinition(context.endpointDefinitions[endpointName]) } else { Object.assign( context.endpointDefinitions[endpointName] || {}, - partialDefinition + partialDefinition, ) } } @@ -338,19 +338,19 @@ export function buildCreateApi, ...Module[]]>( } as Api const initializedModules = modules.map((m) => - m.init(api as any, optionsWithDefaults as any, context) + m.init(api as any, optionsWithDefaults as any, context), ) function injectEndpoints( - inject: Parameters[0] + inject: Parameters[0], ) { const evaluatedEndpoints = inject.endpoints({ - query: (x) => ({ ...x, type: DefinitionType.query } as any), - mutation: (x) => ({ ...x, type: DefinitionType.mutation } as any), + query: (x) => ({ ...x, type: DefinitionType.query }) as any, + mutation: (x) => ({ ...x, type: DefinitionType.mutation }) as any, }) for (const [endpointName, definition] of Object.entries( - evaluatedEndpoints + evaluatedEndpoints, )) { if ( !inject.overrideExisting && @@ -361,7 +361,7 @@ export function buildCreateApi, ...Module[]]>( process.env.NODE_ENV === 'development' ) { console.error( - `called \`injectEndpoints\` to override already-existing endpointName ${endpointName} without specifying \`overrideExisting: true\`` + `called \`injectEndpoints\` to override already-existing endpointName ${endpointName} without specifying \`overrideExisting: true\``, ) } From 335a6ce3b180f162efbb744c0b7c298890aa24bf Mon Sep 17 00:00:00 2001 From: EskiMojo14 Date: Sat, 27 Jan 2024 19:40:11 +0000 Subject: [PATCH 6/9] Revert "try something" This reverts commit 389d5bc86bad1d34d2d189188a0821c173beb27b. --- packages/toolkit/src/query/createApi.ts | 36 ++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/toolkit/src/query/createApi.ts b/packages/toolkit/src/query/createApi.ts index 0159588f1d..ed22f4ec9e 100644 --- a/packages/toolkit/src/query/createApi.ts +++ b/packages/toolkit/src/query/createApi.ts @@ -17,7 +17,7 @@ export interface CreateApiOptions< BaseQuery extends BaseQueryFn, Definitions extends EndpointDefinitions, ReducerPath extends string = 'api', - TagTypes extends string = never, + TagTypes extends string = never > { /** * The base query used by each endpoint if no `queryFn` option is specified. RTK Query exports a utility called [fetchBaseQuery](./fetchBaseQuery) as a lightweight wrapper around `fetch` for common use-cases. See [Customizing Queries](../../rtk-query/usage/customizing-queries) if `fetchBaseQuery` does not handle your requirements. @@ -97,7 +97,7 @@ export interface CreateApiOptions< * Endpoints are just a set of operations that you want to perform against your server. You define them as an object using the builder syntax. There are two basic endpoint types: [`query`](../../rtk-query/usage/queries) and [`mutation`](../../rtk-query/usage/mutations). */ endpoints( - build: EndpointBuilder, + build: EndpointBuilder ): Definitions /** * Defaults to `60` _(this value is in seconds)_. This is how long RTK Query will keep your data cached for **after** the last component unsubscribes. For example, if you query an endpoint, then unmount the component, then mount another component that makes the same request within the given time frame, the most recent value will be served from the cache. @@ -200,7 +200,7 @@ export interface CreateApiOptions< reducerPath, }: { reducerPath: ReducerPath - }, + } ) => | undefined | CombinedState< @@ -220,9 +220,9 @@ export type CreateApi = { BaseQuery extends BaseQueryFn, Definitions extends EndpointDefinitions, ReducerPath extends string = 'api', - TagTypes extends string = never, + TagTypes extends string = never >( - options: CreateApiOptions, + options: CreateApiOptions ): Api } @@ -249,14 +249,14 @@ export type CreateApi = { * @param modules - A variable number of modules that customize how the `createApi` method handles endpoints * @returns A `createApi` method using the provided `modules`. */ -export function buildCreateApi( - ...modules: [...{ [K in keyof Modules]: Module }] -): CreateApi { +export function buildCreateApi, ...Module[]]>( + ...modules: Modules +): CreateApi { return function baseCreateApi(options) { const extractRehydrationInfo = weakMapMemoize((action: UnknownAction) => options.extractRehydrationInfo?.(action, { reducerPath: (options.reducerPath ?? 'api') as any, - }), + }) ) const optionsWithDefaults: CreateApiOptions = { @@ -305,7 +305,7 @@ export function buildCreateApi( apiUid: nanoid(), extractRehydrationInfo, hasRehydrationInfo: weakMapMemoize( - (action) => extractRehydrationInfo(action) != null, + (action) => extractRehydrationInfo(action) != null ), } @@ -321,14 +321,14 @@ export function buildCreateApi( } if (endpoints) { for (const [endpointName, partialDefinition] of Object.entries( - endpoints, + endpoints )) { if (typeof partialDefinition === 'function') { partialDefinition(context.endpointDefinitions[endpointName]) } else { Object.assign( context.endpointDefinitions[endpointName] || {}, - partialDefinition, + partialDefinition ) } } @@ -338,19 +338,19 @@ export function buildCreateApi( } as Api const initializedModules = modules.map((m) => - m.init(api as any, optionsWithDefaults as any, context), + m.init(api as any, optionsWithDefaults as any, context) ) function injectEndpoints( - inject: Parameters[0], + inject: Parameters[0] ) { const evaluatedEndpoints = inject.endpoints({ - query: (x) => ({ ...x, type: DefinitionType.query }) as any, - mutation: (x) => ({ ...x, type: DefinitionType.mutation }) as any, + query: (x) => ({ ...x, type: DefinitionType.query } as any), + mutation: (x) => ({ ...x, type: DefinitionType.mutation } as any), }) for (const [endpointName, definition] of Object.entries( - evaluatedEndpoints, + evaluatedEndpoints )) { if ( !inject.overrideExisting && @@ -361,7 +361,7 @@ export function buildCreateApi( process.env.NODE_ENV === 'development' ) { console.error( - `called \`injectEndpoints\` to override already-existing endpointName ${endpointName} without specifying \`overrideExisting: true\``, + `called \`injectEndpoints\` to override already-existing endpointName ${endpointName} without specifying \`overrideExisting: true\`` ) } From 3244222a9da5bf60535a31d2c4892082612e83db Mon Sep 17 00:00:00 2001 From: EskiMojo14 Date: Sat, 27 Jan 2024 22:46:34 +0000 Subject: [PATCH 7/9] expose options and endpoint definitions under internal key and add buildHooksForApi --- packages/toolkit/src/query/apiTypes.ts | 42 +++-- packages/toolkit/src/query/createApi.ts | 49 +++--- .../toolkit/src/query/react/buildHooks.ts | 136 ++++++++--------- packages/toolkit/src/query/react/index.ts | 11 +- packages/toolkit/src/query/react/module.ts | 144 ++++++++---------- .../src/query/tests/lazyReactHooks.test.tsx | 9 +- 6 files changed, 193 insertions(+), 198 deletions(-) diff --git a/packages/toolkit/src/query/apiTypes.ts b/packages/toolkit/src/query/apiTypes.ts index 2aa7992999..9b40441672 100644 --- a/packages/toolkit/src/query/apiTypes.ts +++ b/packages/toolkit/src/query/apiTypes.ts @@ -23,36 +23,39 @@ export interface ApiModules< // eslint-disable-next-line @typescript-eslint/no-unused-vars ReducerPath extends string, // eslint-disable-next-line @typescript-eslint/no-unused-vars - TagTypes extends string + TagTypes extends string, > {} export type ModuleName = keyof ApiModules +export type DefaultedOptions = + | 'reducerPath' + | 'serializeQueryArgs' + | 'keepUnusedDataFor' + | 'refetchOnMountOrArgChange' + | 'refetchOnFocus' + | 'refetchOnReconnect' + | 'invalidationBehavior' + | 'tagTypes' + export type Module = { name: Name init< BaseQuery extends BaseQueryFn, Definitions extends EndpointDefinitions, ReducerPath extends string, - TagTypes extends string + TagTypes extends string, >( api: Api, options: WithRequiredProp< CreateApiOptions, - | 'reducerPath' - | 'serializeQueryArgs' - | 'keepUnusedDataFor' - | 'refetchOnMountOrArgChange' - | 'refetchOnFocus' - | 'refetchOnReconnect' - | 'invalidationBehavior' - | 'tagTypes' + DefaultedOptions >, - context: ApiContext + context: ApiContext, ): { injectEndpoint( endpointName: string, - definition: EndpointDefinition + definition: EndpointDefinition, ): void } } @@ -62,7 +65,7 @@ export interface ApiContext { endpointDefinitions: Definitions batch(cb: () => void): void extractRehydrationInfo: ( - action: UnknownAction + action: UnknownAction, ) => CombinedState | undefined hasRehydrationInfo: (action: UnknownAction) => boolean } @@ -72,7 +75,7 @@ export type Api< Definitions extends EndpointDefinitions, ReducerPath extends string, TagTypes extends string, - Enhancers extends ModuleName = CoreModule + Enhancers extends ModuleName = CoreModule, > = UnionToIntersection< ApiModules[Enhancers] > & { @@ -81,7 +84,7 @@ export type Api< */ injectEndpoints(_: { endpoints: ( - build: EndpointBuilder + build: EndpointBuilder, ) => NewDefinitions overrideExisting?: boolean }): Api< @@ -96,7 +99,7 @@ export type Api< */ enhanceEndpoints< NewTagTypes extends string = never, - NewDefinitions extends EndpointDefinitions = never + NewDefinitions extends EndpointDefinitions = never, >(_: { addTagTypes?: readonly NewTagTypes[] endpoints?: UpdateDefinitions< @@ -117,4 +120,11 @@ export type Api< TagTypes | NewTagTypes, Enhancers > + internal: { + options: WithRequiredProp< + CreateApiOptions, + DefaultedOptions + > + endpoints: Definitions + } } diff --git a/packages/toolkit/src/query/createApi.ts b/packages/toolkit/src/query/createApi.ts index ed22f4ec9e..9e71028262 100644 --- a/packages/toolkit/src/query/createApi.ts +++ b/packages/toolkit/src/query/createApi.ts @@ -1,4 +1,10 @@ -import type { Api, ApiContext, Module, ModuleName } from './apiTypes' +import type { + Api, + ApiContext, + DefaultedOptions, + Module, + ModuleName, +} from './apiTypes' import type { CombinedState } from './core/apiState' import type { BaseQueryArg, BaseQueryFn } from './baseQueryTypes' import type { SerializeQueryArgs } from './defaultSerializeQueryArgs' @@ -10,14 +16,14 @@ import type { import { DefinitionType, isQueryDefinition } from './endpointDefinitions' import { nanoid } from './core/rtkImports' import type { UnknownAction } from '@reduxjs/toolkit' -import type { NoInfer } from './tsHelpers' +import type { NoInfer, WithRequiredProp } from './tsHelpers' import { weakMapMemoize } from 'reselect' export interface CreateApiOptions< BaseQuery extends BaseQueryFn, Definitions extends EndpointDefinitions, ReducerPath extends string = 'api', - TagTypes extends string = never + TagTypes extends string = never, > { /** * The base query used by each endpoint if no `queryFn` option is specified. RTK Query exports a utility called [fetchBaseQuery](./fetchBaseQuery) as a lightweight wrapper around `fetch` for common use-cases. See [Customizing Queries](../../rtk-query/usage/customizing-queries) if `fetchBaseQuery` does not handle your requirements. @@ -97,7 +103,7 @@ export interface CreateApiOptions< * Endpoints are just a set of operations that you want to perform against your server. You define them as an object using the builder syntax. There are two basic endpoint types: [`query`](../../rtk-query/usage/queries) and [`mutation`](../../rtk-query/usage/mutations). */ endpoints( - build: EndpointBuilder + build: EndpointBuilder, ): Definitions /** * Defaults to `60` _(this value is in seconds)_. This is how long RTK Query will keep your data cached for **after** the last component unsubscribes. For example, if you query an endpoint, then unmount the component, then mount another component that makes the same request within the given time frame, the most recent value will be served from the cache. @@ -200,7 +206,7 @@ export interface CreateApiOptions< reducerPath, }: { reducerPath: ReducerPath - } + }, ) => | undefined | CombinedState< @@ -220,9 +226,9 @@ export type CreateApi = { BaseQuery extends BaseQueryFn, Definitions extends EndpointDefinitions, ReducerPath extends string = 'api', - TagTypes extends string = never + TagTypes extends string = never, >( - options: CreateApiOptions + options: CreateApiOptions, ): Api } @@ -256,10 +262,13 @@ export function buildCreateApi, ...Module[]]>( const extractRehydrationInfo = weakMapMemoize((action: UnknownAction) => options.extractRehydrationInfo?.(action, { reducerPath: (options.reducerPath ?? 'api') as any, - }) + }), ) - const optionsWithDefaults: CreateApiOptions = { + const optionsWithDefaults: WithRequiredProp< + CreateApiOptions, + DefaultedOptions + > = { reducerPath: 'api', keepUnusedDataFor: 60, refetchOnMountOrArgChange: false, @@ -305,7 +314,7 @@ export function buildCreateApi, ...Module[]]>( apiUid: nanoid(), extractRehydrationInfo, hasRehydrationInfo: weakMapMemoize( - (action) => extractRehydrationInfo(action) != null + (action) => extractRehydrationInfo(action) != null, ), } @@ -321,36 +330,40 @@ export function buildCreateApi, ...Module[]]>( } if (endpoints) { for (const [endpointName, partialDefinition] of Object.entries( - endpoints + endpoints, )) { if (typeof partialDefinition === 'function') { partialDefinition(context.endpointDefinitions[endpointName]) } else { Object.assign( context.endpointDefinitions[endpointName] || {}, - partialDefinition + partialDefinition, ) } } } return api }, + internal: { + options: optionsWithDefaults, + endpoints: context.endpointDefinitions, + }, } as Api const initializedModules = modules.map((m) => - m.init(api as any, optionsWithDefaults as any, context) + m.init(api as any, optionsWithDefaults, context), ) function injectEndpoints( - inject: Parameters[0] + inject: Parameters[0], ) { const evaluatedEndpoints = inject.endpoints({ - query: (x) => ({ ...x, type: DefinitionType.query } as any), - mutation: (x) => ({ ...x, type: DefinitionType.mutation } as any), + query: (x) => ({ ...x, type: DefinitionType.query }) as any, + mutation: (x) => ({ ...x, type: DefinitionType.mutation }) as any, }) for (const [endpointName, definition] of Object.entries( - evaluatedEndpoints + evaluatedEndpoints, )) { if ( !inject.overrideExisting && @@ -361,7 +374,7 @@ export function buildCreateApi, ...Module[]]>( process.env.NODE_ENV === 'development' ) { console.error( - `called \`injectEndpoints\` to override already-existing endpointName ${endpointName} without specifying \`overrideExisting: true\`` + `called \`injectEndpoints\` to override already-existing endpointName ${endpointName} without specifying \`overrideExisting: true\``, ) } diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts index 5a524719cf..10816655a1 100644 --- a/packages/toolkit/src/query/react/buildHooks.ts +++ b/packages/toolkit/src/query/react/buildHooks.ts @@ -61,7 +61,7 @@ export const useIsomorphicLayoutEffect = : useEffect export interface QueryHooks< - Definition extends QueryDefinition + Definition extends QueryDefinition, > { useQuery: UseQuery useLazyQuery: UseLazyQuery @@ -71,7 +71,7 @@ export interface QueryHooks< } export interface MutationHooks< - Definition extends MutationDefinition + Definition extends MutationDefinition, > { useMutation: UseMutation } @@ -92,15 +92,15 @@ export interface MutationHooks< * - Re-renders as the request status changes and data becomes available */ export type UseQuery> = < - R extends Record = UseQueryStateDefaultResult + R extends Record = UseQueryStateDefaultResult, >( arg: QueryArgFrom | SkipToken, - options?: UseQuerySubscriptionOptions & UseQueryStateOptions + options?: UseQuerySubscriptionOptions & UseQueryStateOptions, ) => UseQueryHookResult export type UseQueryHookResult< D extends QueryDefinition, - R = UseQueryStateDefaultResult + R = UseQueryStateDefaultResult, > = UseQueryStateResult & UseQuerySubscriptionResult /** @@ -113,7 +113,7 @@ export type TypedUseQueryHookResult< BaseQuery extends BaseQueryFn, R = UseQueryStateDefaultResult< QueryDefinition - > + >, > = TypedUseQueryStateResult & TypedUseQuerySubscriptionResult @@ -176,14 +176,14 @@ interface UseQuerySubscriptionOptions extends SubscriptionOptions { * - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met */ export type UseQuerySubscription< - D extends QueryDefinition + D extends QueryDefinition, > = ( arg: QueryArgFrom | SkipToken, - options?: UseQuerySubscriptionOptions + options?: UseQuerySubscriptionOptions, ) => UseQuerySubscriptionResult export type UseQuerySubscriptionResult< - D extends QueryDefinition + D extends QueryDefinition, > = Pick, 'refetch'> /** @@ -193,13 +193,13 @@ export type UseQuerySubscriptionResult< export type TypedUseQuerySubscriptionResult< ResultType, QueryArg, - BaseQuery extends BaseQueryFn + BaseQuery extends BaseQueryFn, > = UseQuerySubscriptionResult< QueryDefinition > export type UseLazyQueryLastPromiseInfo< - D extends QueryDefinition + D extends QueryDefinition, > = { lastArg: QueryArgFrom } @@ -222,13 +222,13 @@ export type UseLazyQueryLastPromiseInfo< * When the trigger function returned from a LazyQuery is called, it always initiates a new request to the server even if there is cached data. Set `preferCacheValue`(the second argument to the function) as `true` if you want it to immediately return a cached value if one exists. */ export type UseLazyQuery> = < - R extends Record = UseQueryStateDefaultResult + R extends Record = UseQueryStateDefaultResult, >( - options?: SubscriptionOptions & Omit, 'skip'> + options?: SubscriptionOptions & Omit, 'skip'>, ) => [ LazyQueryTrigger, UseQueryStateResult, - UseLazyQueryLastPromiseInfo + UseLazyQueryLastPromiseInfo, ] export type LazyQueryTrigger> = { @@ -254,7 +254,7 @@ export type LazyQueryTrigger> = { */ ( arg: QueryArgFrom, - preferCacheValue?: boolean + preferCacheValue?: boolean, ): QueryActionCreatorResult } @@ -270,14 +270,14 @@ export type LazyQueryTrigger> = { * - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met and the fetch has been manually called at least once */ export type UseLazyQuerySubscription< - D extends QueryDefinition + D extends QueryDefinition, > = ( - options?: SubscriptionOptions + options?: SubscriptionOptions, ) => readonly [LazyQueryTrigger, QueryArgFrom | UninitializedValue] export type QueryStateSelector< R extends Record, - D extends QueryDefinition + D extends QueryDefinition, > = (state: UseQueryStateDefaultResult) => R /** @@ -291,15 +291,15 @@ export type QueryStateSelector< * - Re-renders as the request status changes and data becomes available */ export type UseQueryState> = < - R extends Record = UseQueryStateDefaultResult + R extends Record = UseQueryStateDefaultResult, >( arg: QueryArgFrom | SkipToken, - options?: UseQueryStateOptions + options?: UseQueryStateOptions, ) => UseQueryStateResult export type UseQueryStateOptions< D extends QueryDefinition, - R extends Record + R extends Record, > = { /** * Prevents a query from automatically running. @@ -369,7 +369,7 @@ export type UseQueryStateOptions< export type UseQueryStateResult< _ extends QueryDefinition, - R + R, > = TSHelpersNoInfer /** @@ -382,7 +382,7 @@ export type TypedUseQueryStateResult< BaseQuery extends BaseQueryFn, R = UseQueryStateDefaultResult< QueryDefinition - > + >, > = TSHelpersNoInfer type UseQueryStateBaseResult> = @@ -459,12 +459,12 @@ type UseQueryStateDefaultResult> = export type MutationStateSelector< R extends Record, - D extends MutationDefinition + D extends MutationDefinition, > = (state: MutationResultSelectorResult) => R export type UseMutationStateOptions< D extends MutationDefinition, - R extends Record + R extends Record, > = { selectFromResult?: MutationStateSelector fixedCacheKey?: string @@ -472,7 +472,7 @@ export type UseMutationStateOptions< export type UseMutationStateResult< D extends MutationDefinition, - R + R, > = TSHelpersNoInfer & { originalArgs?: QueryArgFrom /** @@ -492,7 +492,7 @@ export type TypedUseMutationResult< BaseQuery extends BaseQueryFn, R = MutationResultSelectorResult< MutationDefinition - > + >, > = UseMutationStateResult< MutationDefinition, R @@ -509,9 +509,9 @@ export type TypedUseMutationResult< * - Re-renders as the request status changes and data becomes available */ export type UseMutation> = < - R extends Record = MutationResultSelectorResult + R extends Record = MutationResultSelectorResult, >( - options?: UseMutationStateOptions + options?: UseMutationStateOptions, ) => readonly [MutationTrigger, UseMutationStateResult] export type MutationTrigger> = @@ -542,7 +542,7 @@ export type MutationTrigger> = * to prevent that the library user has to do an additional check for `isUninitialized`/ */ const noPendingQueryStateSelector: QueryStateSelector = ( - selected + selected, ) => { if (selected.isUninitialized) { return { @@ -559,7 +559,7 @@ const noPendingQueryStateSelector: QueryStateSelector = ( type GenericPrefetchThunk = ( endpointName: any, arg: any, - options: PrefetchOptions + options: PrefetchOptions, ) => ThunkAction /** @@ -579,16 +579,16 @@ export function buildHooks({ createSelector, }, serializeQueryArgs, - context, + endpointDefinitions, }: { api: Api moduleOptions: Required serializeQueryArgs: SerializeQueryArgs - context: ApiContext + endpointDefinitions: Definitions }) { const usePossiblyImmediateEffect: ( effect: () => void | undefined, - deps?: DependencyList + deps?: DependencyList, ) => void = unstable__sideEffectsInRender ? (cb) => cb() : useEffect return { buildQueryHooks, buildMutationHook, usePrefetch } @@ -596,14 +596,14 @@ export function buildHooks({ function queryStatePreSelector( currentState: QueryResultSelectorResult, lastResult: UseQueryStateDefaultResult | undefined, - queryArgs: any + queryArgs: any, ): UseQueryStateDefaultResult { // if we had a last result and the current result is uninitialized, // we might have called `api.util.resetApiState` // in this case, reset the hook if (lastResult?.endpointName && currentState.isUninitialized) { const { endpointName } = lastResult - const endpointDefinition = context.endpointDefinitions[endpointName] + const endpointDefinition = endpointDefinitions[endpointName] if ( serializeQueryArgs({ queryArgs: lastResult.originalArgs, @@ -644,7 +644,7 @@ export function buildHooks({ function usePrefetch>( endpointName: EndpointName, - defaultOptions?: PrefetchOptions + defaultOptions?: PrefetchOptions, ) { const dispatch = useDispatch>() const stableDefaultOptions = useShallowStableValue(defaultOptions) @@ -655,9 +655,9 @@ export function buildHooks({ (api.util.prefetch as GenericPrefetchThunk)(endpointName, arg, { ...stableDefaultOptions, ...options, - }) + }), ), - [endpointName, dispatch, stableDefaultOptions] + [endpointName, dispatch, stableDefaultOptions], ) } @@ -671,7 +671,7 @@ export function buildHooks({ skip = false, pollingInterval = 0, skipPollingIfUnfocused = false, - } = {} + } = {}, ) => { const { initiate } = api.endpoints[name] as ApiEndpointQuery< QueryDefinition, @@ -681,7 +681,7 @@ export function buildHooks({ const subscriptionSelectorsRef = useRef() if (!subscriptionSelectorsRef.current) { const returnedValue = dispatch( - api.internalActions.internal_getRTKQSubscriptions() + api.internalActions.internal_getRTKQSubscriptions(), ) if (process.env.NODE_ENV !== 'production') { @@ -691,7 +691,7 @@ export function buildHooks({ ) { throw new Error( `Warning: Middleware for RTK-Query API at reducerPath "${api.reducerPath}" has not been added to the store. - You must add the middleware for RTK-Query to function correctly!` + You must add the middleware for RTK-Query to function correctly!`, ) } } @@ -707,8 +707,8 @@ export function buildHooks({ // with a case where the query args did change but the serialization doesn't, // and then we never try to initiate a refetch. defaultSerializeQueryArgs, - context.endpointDefinitions[name], - name + endpointDefinitions[name], + name, ) const stableSubscriptionOptions = useShallowStableValue({ refetchOnReconnect, @@ -730,7 +730,7 @@ export function buildHooks({ currentRenderHasSubscription = subscriptionSelectorsRef.current.isRequestSubscribed( queryCacheKey, - requestId + requestId, ) } @@ -771,7 +771,7 @@ export function buildHooks({ initiate(stableArg, { subscriptionOptions: stableSubscriptionOptions, forceRefetch: refetchOnMountOrArgChange, - }) + }), ) promiseRef.current = promise @@ -802,12 +802,12 @@ export function buildHooks({ refetch: () => { if (!promiseRef.current) throw new Error( - 'Cannot refetch a query that has not been started yet.' + 'Cannot refetch a query that has not been started yet.', ) return promiseRef.current?.refetch() }, }), - [] + [], ) } @@ -838,7 +838,7 @@ export function buildHooks({ if (stableSubscriptionOptions !== lastSubscriptionOptions) { promiseRef.current?.updateSubscriptionOptions( - stableSubscriptionOptions + stableSubscriptionOptions, ) } }, [stableSubscriptionOptions]) @@ -859,7 +859,7 @@ export function buildHooks({ initiate(arg, { subscriptionOptions: subscriptionOptionsRef.current, forceRefetch: !preferCacheValue, - }) + }), ) setArg(arg) @@ -867,7 +867,7 @@ export function buildHooks({ return promise! }, - [dispatch, initiate] + [dispatch, initiate], ) /* cleanup on unmount */ @@ -889,7 +889,7 @@ export function buildHooks({ const useQueryState: UseQueryState = ( arg: any, - { skip = false, selectFromResult } = {} + { skip = false, selectFromResult } = {}, ) => { const { select } = api.endpoints[name] as ApiEndpointQuery< QueryDefinition, @@ -898,8 +898,8 @@ export function buildHooks({ const stableArg = useStableQueryArgs( skip ? skipToken : arg, serializeQueryArgs, - context.endpointDefinitions[name], - name + endpointDefinitions[name], + name, ) type ApiRootState = Parameters>[0] @@ -919,9 +919,9 @@ export function buildHooks({ memoizeOptions: { resultEqualityCheck: shallowEqual, }, - } + }, ), - [select, stableArg] + [select, stableArg], ) const querySelector: Selector = useMemo( @@ -931,19 +931,19 @@ export function buildHooks({ devModeChecks: { identityFunctionCheck: 'never' }, }) : selectDefaultResult, - [selectDefaultResult, selectFromResult] + [selectDefaultResult, selectFromResult], ) const currentState = useSelector( (state: RootState) => querySelector(state, lastValue.current), - shallowEqual + shallowEqual, ) const store = useStore>() const newLastValue = selectDefaultResult( store.getState(), - lastValue.current + lastValue.current, ) useIsomorphicLayoutEffect(() => { lastValue.current = newLastValue @@ -966,7 +966,7 @@ export function buildHooks({ const info = useMemo(() => ({ lastArg: arg }), [arg]) return useMemo( () => [trigger, queryStateResults, info], - [trigger, queryStateResults, info] + [trigger, queryStateResults, info], ) }, useQuery(arg, options) { @@ -985,7 +985,7 @@ export function buildHooks({ return useMemo( () => ({ ...queryStateResults, ...querySubscriptionResults }), - [queryStateResults, querySubscriptionResults] + [queryStateResults, querySubscriptionResults], ) }, } @@ -1006,7 +1006,7 @@ export function buildHooks({ promise?.reset() } }, - [promise] + [promise], ) const triggerMutation = useCallback( @@ -1015,20 +1015,20 @@ export function buildHooks({ setPromise(promise) return promise }, - [dispatch, initiate, fixedCacheKey] + [dispatch, initiate, fixedCacheKey], ) const { requestId } = promise || {} const selectDefaultResult = useMemo( () => select({ fixedCacheKey, requestId: promise?.requestId }), - [fixedCacheKey, promise, select] + [fixedCacheKey, promise, select], ) const mutationSelector = useMemo( (): Selector, any> => selectFromResult ? createSelector([selectDefaultResult], selectFromResult) : selectDefaultResult, - [selectFromResult, selectDefaultResult] + [selectFromResult, selectDefaultResult], ) const currentState = useSelector(mutationSelector, shallowEqual) @@ -1044,7 +1044,7 @@ export function buildHooks({ api.internalActions.removeMutationResult({ requestId, fixedCacheKey, - }) + }), ) } }) @@ -1071,12 +1071,12 @@ export function buildHooks({ const finalState = useMemo( () => ({ ...currentState, originalArgs, reset }), - [currentState, originalArgs, reset] + [currentState, originalArgs, reset], ) return useMemo( () => [triggerMutation, finalState] as const, - [triggerMutation, finalState] + [triggerMutation, finalState], ) } } diff --git a/packages/toolkit/src/query/react/index.ts b/packages/toolkit/src/query/react/index.ts index b49249a713..db6f981417 100644 --- a/packages/toolkit/src/query/react/index.ts +++ b/packages/toolkit/src/query/react/index.ts @@ -6,8 +6,7 @@ import { buildCreateApi, coreModule } from '@reduxjs/toolkit/query' import { reactHooksModule, reactHooksModuleName, - lazyReactHooksModule, - lazyReactHooksModuleName, + buildHooksForApi, } from './module' export * from '@reduxjs/toolkit/query' @@ -24,10 +23,4 @@ export type { TypedUseQueryStateResult, TypedUseQuerySubscriptionResult, } from './buildHooks' -export { - createApi, - reactHooksModule, - reactHooksModuleName, - lazyReactHooksModule, - lazyReactHooksModuleName, -} +export { createApi, reactHooksModule, reactHooksModuleName, buildHooksForApi } diff --git a/packages/toolkit/src/query/react/module.ts b/packages/toolkit/src/query/react/module.ts index 7b2ba19b23..82d87360d4 100644 --- a/packages/toolkit/src/query/react/module.ts +++ b/packages/toolkit/src/query/react/module.ts @@ -1,12 +1,13 @@ -import type { - Api, - ApiModules, - BaseQueryFn, - EndpointDefinitions, - Module, - MutationDefinition, - QueryArgFrom, - QueryDefinition, +import { + type Api, + type ApiModules, + type BaseQueryFn, + type EndpointDefinitions, + type Module, + type MutationDefinition, + type QueryArgFrom, + type QueryDefinition, + type CoreModule, } from '@reduxjs/toolkit/query' import { isMutationDefinition, isQueryDefinition } from '../endpointDefinitions' import { safeAssign } from '../tsHelpers' @@ -26,14 +27,10 @@ import { createSelector as _createSelector } from 'reselect' import type { QueryKeys } from '../core/apiState' import type { PrefetchOptions } from '../core/module' import { countObjectKeys } from '../utils/countObjectKeys' -import { t } from 'vitest/dist/reporters-qc5Smpt5' export const reactHooksModuleName = /* @__PURE__ */ Symbol() export type ReactHooksModule = typeof reactHooksModuleName -export const lazyReactHooksModuleName = /* @__PURE__ */ Symbol() -export type LazyReactHooksModule = typeof lazyReactHooksModuleName - declare module '@reduxjs/toolkit/query' { export interface ApiModules< // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -44,16 +41,6 @@ declare module '@reduxjs/toolkit/query' { // eslint-disable-next-line @typescript-eslint/no-unused-vars TagTypes extends string, > { - [lazyReactHooksModuleName]: { - buildHooks( - options?: ReactHooksModuleOptions, - ): ApiModules< - BaseQuery, - Definitions, - ReducerPath, - TagTypes - >[ReactHooksModule] - } [reactHooksModuleName]: { /** * Endpoints based on the input endpoints provided to `createApi`, containing `select`, `hooks` and `action matchers`. @@ -135,7 +122,10 @@ export interface ReactHooksModuleOptions { } function buildInjectEndpoint( - target: ApiModules, any, any>[ReactHooksModule], + target: Omit< + ApiModules, any, any>[ReactHooksModule], + 'usePrefetch' + >, { buildMutationHook, buildQueryHooks, @@ -264,7 +254,7 @@ export const reactHooksModule = ( createSelector, }, serializeQueryArgs, - context, + endpointDefinitions: context.endpointDefinitions, }) safeAssign(anyApi, { usePrefetch }) @@ -280,63 +270,55 @@ export const reactHooksModule = ( } } -export const lazyReactHooksModule = ( - moduleOptions?: ReactHooksModuleOptions, -): Module => ({ - name: lazyReactHooksModuleName, - init(api, { serializeQueryArgs }, context) { - const anyApi = api as any as Api< - any, - Record, - any, - any, - LazyReactHooksModule - > - - function buildEndpointHooks(options?: ReactHooksModuleOptions) { - const { batch, hooks, unstable__sideEffectsInRender, createSelector } = { - ...defaultOptions, - ...moduleOptions, - ...options, - } - const { buildQueryHooks, buildMutationHook, usePrefetch } = buildHooks({ - api, - moduleOptions: { - batch, - hooks, - unstable__sideEffectsInRender, - createSelector, - }, - serializeQueryArgs, - context, - }) - - const result: { - endpoints: Record | MutationHooks> - usePrefetch: typeof usePrefetch - } = { - endpoints: {}, - usePrefetch, - } +export const buildHooksForApi = < + BaseQuery extends BaseQueryFn, + Definitions extends EndpointDefinitions, + ReducerPath extends string, + TagTypes extends string, +>( + api: Api, + options?: ReactHooksModuleOptions, +): ApiModules< + BaseQuery, + Definitions, + ReducerPath, + TagTypes +>[ReactHooksModule] => { + const { batch, hooks, unstable__sideEffectsInRender, createSelector } = { + ...defaultOptions, + ...options, + } - const injectEndpoint = buildInjectEndpoint(result, { - buildMutationHook, - buildQueryHooks, - }) + const { buildQueryHooks, buildMutationHook, usePrefetch } = buildHooks({ + api, + moduleOptions: { + batch, + hooks, + unstable__sideEffectsInRender, + createSelector, + }, + serializeQueryArgs: api.internal.options.serializeQueryArgs, + endpointDefinitions: api.internal.endpoints, + }) - for (const [endpointName, definition] of Object.entries( - context.endpointDefinitions, - )) { - result.endpoints[endpointName] = {} as any - injectEndpoint(endpointName, definition) - } - return result - } + const result: { + endpoints: Record | MutationHooks> + usePrefetch: typeof usePrefetch + } = { + endpoints: {}, + usePrefetch, + } - safeAssign(anyApi, { buildHooks: buildEndpointHooks }) + const injectEndpoint = buildInjectEndpoint(result, { + buildMutationHook, + buildQueryHooks, + }) - return { - injectEndpoint() {}, - } - }, -}) + for (const [endpointName, definition] of Object.entries( + api.internal.endpoints, + )) { + result.endpoints[endpointName] = {} as any + injectEndpoint(endpointName, definition) + } + return result as any +} diff --git a/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx b/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx index 269193420c..107a8ecd78 100644 --- a/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx +++ b/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx @@ -1,9 +1,6 @@ import { delay } from 'msw' -import { coreModule } from '../core' -import { buildCreateApi } from '../createApi' -import { fakeBaseQuery, lazyReactHooksModule } from '../react' - -const createApi = buildCreateApi(coreModule(), lazyReactHooksModule()) +import { buildHooksForApi, fakeBaseQuery } from '../react' +import { createApi } from '../core' interface Post { id: number @@ -42,7 +39,7 @@ describe('lazy react hooks', () => { expect(api.endpoints.deletePost).not.toHaveProperty('useMutation') expect(api).not.toHaveProperty('useDeletePostMutation') - const hooks = api.buildHooks() + const hooks = buildHooksForApi(api) expect(hooks.endpoints.getPost).toEqual({ useLazyQuery: expect.any(Function), From 7dd2a78a9d3a85be49d0b9214f06b6aded6f4c9d Mon Sep 17 00:00:00 2001 From: EskiMojo14 Date: Sat, 27 Jan 2024 23:00:22 +0000 Subject: [PATCH 8/9] tweak imports --- packages/toolkit/src/query/react/module.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/toolkit/src/query/react/module.ts b/packages/toolkit/src/query/react/module.ts index 82d87360d4..7d984637c4 100644 --- a/packages/toolkit/src/query/react/module.ts +++ b/packages/toolkit/src/query/react/module.ts @@ -1,13 +1,12 @@ -import { - type Api, - type ApiModules, - type BaseQueryFn, - type EndpointDefinitions, - type Module, - type MutationDefinition, - type QueryArgFrom, - type QueryDefinition, - type CoreModule, +import type { + Api, + ApiModules, + BaseQueryFn, + EndpointDefinitions, + Module, + MutationDefinition, + QueryArgFrom, + QueryDefinition, } from '@reduxjs/toolkit/query' import { isMutationDefinition, isQueryDefinition } from '../endpointDefinitions' import { safeAssign } from '../tsHelpers' @@ -276,7 +275,7 @@ export const buildHooksForApi = < ReducerPath extends string, TagTypes extends string, >( - api: Api, + api: Api, options?: ReactHooksModuleOptions, ): ApiModules< BaseQuery, From 18a021aa02f8fea264c8fc8db8690ac820ef5381 Mon Sep 17 00:00:00 2001 From: EskiMojo14 Date: Sat, 27 Jan 2024 23:22:35 +0000 Subject: [PATCH 9/9] use the right imports --- packages/toolkit/src/query/tests/lazyReactHooks.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx b/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx index 107a8ecd78..481efe26da 100644 --- a/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx +++ b/packages/toolkit/src/query/tests/lazyReactHooks.test.tsx @@ -1,6 +1,6 @@ import { delay } from 'msw' -import { buildHooksForApi, fakeBaseQuery } from '../react' -import { createApi } from '../core' +import { createApi } from '@reduxjs/toolkit/query' +import { buildHooksForApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react' interface Post { id: number