@reduxjs/toolkit
Version:
The official, opinionated, batteries-included toolset for efficient Redux development
158 lines (149 loc) • 5.09 kB
text/typescript
import type { MutationHooks, QueryHooks } from './buildHooks'
import { buildHooks } from './buildHooks'
import { isQueryDefinition, isMutationDefinition } from '../endpointDefinitions'
import type {
EndpointDefinitions,
QueryDefinition,
MutationDefinition,
QueryArgFrom,
} from '@reduxjs/toolkit/dist/query/endpointDefinitions'
import type { Api, Module } from '../apiTypes'
import { capitalize } from '../utils'
import { safeAssign } from '../tsHelpers'
import type { BaseQueryFn } from '@reduxjs/toolkit/dist/query/baseQueryTypes'
import type { HooksWithUniqueNames } from './versionedTypes'
import {
useDispatch as rrUseDispatch,
useSelector as rrUseSelector,
useStore as rrUseStore,
batch as rrBatch,
} from 'react-redux'
import type { QueryKeys } from '../core/apiState'
import type { PrefetchOptions } from '../core/module'
export const reactHooksModuleName = /* @__PURE__ */ Symbol()
export type ReactHooksModule = typeof reactHooksModuleName
declare module '@reduxjs/toolkit/dist/query/apiTypes' {
export interface ApiModules<
// eslint-disable-next-line @typescript-eslint/no-unused-vars
BaseQuery extends BaseQueryFn,
Definitions extends EndpointDefinitions,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
ReducerPath extends string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
TagTypes extends string
> {
[reactHooksModuleName]: {
/**
* Endpoints based on the input endpoints provided to `createApi`, containing `select`, `hooks` and `action matchers`.
*/
endpoints: {
[K in keyof Definitions]: Definitions[K] extends QueryDefinition<
any,
any,
any,
any,
any
>
? QueryHooks<Definitions[K]>
: Definitions[K] extends MutationDefinition<any, any, any, any, any>
? MutationHooks<Definitions[K]>
: 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 extends QueryKeys<Definitions>>(
endpointName: EndpointName,
options?: PrefetchOptions
): (
arg: QueryArgFrom<Definitions[EndpointName]>,
options?: PrefetchOptions
) => void
} & HooksWithUniqueNames<Definitions>
}
}
type RR = typeof import('react-redux')
export interface ReactHooksModuleOptions {
/**
* The version of the `batchedUpdates` function to be used
*/
batch?: RR['batch']
/**
* The version of the `useDispatch` hook to be used
*/
useDispatch?: RR['useDispatch']
/**
* The version of the `useSelector` hook to be used
*/
useSelector?: RR['useSelector']
/**
* The version of the `useStore` hook to be used
*/
useStore?: RR['useStore']
}
/**
* Creates a module that generates react hooks from endpoints, for use with `buildCreateApi`.
*
* @example
* ```ts
* const MyContext = React.createContext<ReactReduxContextValue>(null as any);
* const customCreateApi = buildCreateApi(
* coreModule(),
* reactHooksModule({ useDispatch: createDispatchHook(MyContext) })
* );
* ```
*
* @returns A module for use with `buildCreateApi`
*/
export const reactHooksModule = ({
batch = rrBatch,
useDispatch = rrUseDispatch,
useSelector = rrUseSelector,
useStore = rrUseStore,
}: ReactHooksModuleOptions = {}): Module<ReactHooksModule> => ({
name: reactHooksModuleName,
init(api, options, context) {
const anyApi = api as any as Api<
any,
Record<string, any>,
string,
string,
ReactHooksModule
>
const { buildQueryHooks, buildMutationHook, usePrefetch } = buildHooks({
api,
moduleOptions: { batch, useDispatch, useSelector, useStore },
})
safeAssign(anyApi, { usePrefetch })
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
}
},
}
},
})