API: createApi reference">API: createApi reference">
跳至主要内容

createApi

createApi 是 RTK Query 功能的核心。它允许您定义一组“端点”,这些端点描述如何从后端 API 和其他异步来源检索数据,包括配置如何获取和转换这些数据。它生成一个“API 切片”结构,其中包含 Redux 逻辑(以及可选的 React Hooks),这些逻辑封装了为您进行数据获取和缓存的过程。

提示

通常,您应该每个应用程序需要通信的基 URL 只有一个 API 切片。例如,如果您的网站从 /api/posts/api/users 获取数据,您将拥有一个带有 /api/ 作为基 URL 的单个 API 切片,以及 postsusers 的单独端点定义。这使您可以通过跨端点定义 标签 关系来有效地利用 自动重新获取

出于可维护性目的,您可能希望将端点定义拆分到多个文件中,同时仍然保持一个包含所有这些端点的单个 API 切片。有关如何使用 injectEndpoints 属性将 API 端点从其他文件注入到单个 API 切片定义中,请参见 代码拆分

示例:src/services/pokemon.ts
// Need to use the React-specific entry point to allow generating React hooks
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import type { Pokemon } from './types'

// Define a service using a base URL and expected endpoints
export const pokemonApi = createApi({
reducerPath: 'pokemonApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
endpoints: (builder) => ({
getPokemonByName: builder.query<Pokemon, string>({
query: (name) => `pokemon/${name}`,
}),
}),
})

// Export hooks for usage in function components, which are
// auto-generated based on the defined endpoints
export const { useGetPokemonByNameQuery } = pokemonApi

参数

createApi 接受一个带有以下选项的单个配置对象参数

  baseQuery(args: InternalQueryArgs, api: BaseQueryApi, extraOptions?: DefinitionExtraOptions): any;
endpoints(build: EndpointBuilder<InternalQueryArgs, TagTypes>): Definitions;
extractRehydrationInfo?: (
action: UnknownAction,
{
reducerPath,
}: {
reducerPath: ReducerPath
}
) =>
| undefined
| CombinedState<Definitions, TagTypes, ReducerPath>
tagTypes?: readonly TagTypes[];
reducerPath?: ReducerPath;
serializeQueryArgs?: SerializeQueryArgs<InternalQueryArgs>;
keepUnusedDataFor?: number; // value is in seconds
refetchOnMountOrArgChange?: boolean | number; // value is in seconds
refetchOnFocus?: boolean;
refetchOnReconnect?: boolean;

baseQuery

如果未指定 queryFn 选项,则每个端点使用的基本查询。RTK Query 导出一个名为 fetchBaseQuery 的实用程序,作为 fetch 的轻量级包装器,用于常见用例。如果 fetchBaseQuery 不能满足您的要求,请参见 自定义查询

baseQuery 函数参数

  • args - 给定端点的 query 函数的返回值
  • api - BaseQueryApi 对象包含
    • signal - 一个 AbortSignal 对象,可用于中止 DOM 请求和/或读取请求是否已中止。
    • abort - 附加到 signal 的 AbortController 的 abort() 方法。
    • dispatch - 对应 Redux 存储的 store.dispatch 方法
    • getState - 一个可以被调用以访问当前存储状态的函数
    • extra - 作为 thunk.extraArgument 提供给 configureStore getDefaultMiddleware 选项。
    • endpoint - 端点的名称。
    • type - 请求类型(querymutation)。
    • forced - 指示查询是否已被强制。
  • extraOptions - 为给定端点提供的可选 extraOptions 属性的值

baseQuery 函数签名

基本查询签名
export type BaseQueryFn<
Args = any,
Result = unknown,
Error = unknown,
DefinitionExtraOptions = {},
Meta = {},
> = (
args: Args,
api: BaseQueryApi,
extraOptions: DefinitionExtraOptions,
) => MaybePromise<QueryReturnValue<Result, Error, Meta>>

export interface BaseQueryApi {
signal: AbortSignal
abort: (reason?: string) => void
dispatch: ThunkDispatch<any, any, any>
getState: () => unknown
extra: unknown
endpoint: string
type: 'query' | 'mutation'
forced?: boolean
}

export type QueryReturnValue<T = unknown, E = unknown, M = unknown> =
| {
error: E
data?: undefined
meta?: M
}
| {
error?: undefined
data: T
meta?: M
}
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (build) => ({
// ...endpoints
}),
})

endpoints

端点只是一组您想要对服务器执行的操作。您可以使用构建器语法将它们定义为一个对象。有两种基本端点类型:querymutation

有关各个属性的详细信息,请参见 端点的结构

查询端点定义

查询端点定义
export type QueryDefinition<
QueryArg,
BaseQuery extends BaseQueryFn,
TagTypes extends string,
ResultType,
ReducerPath extends string = string,
> = {
query(arg: QueryArg): BaseQueryArg<BaseQuery>

/* either `query` or `queryFn` can be present, but not both simultaneously */
queryFn(
arg: QueryArg,
api: BaseQueryApi,
extraOptions: BaseQueryExtraOptions<BaseQuery>,
baseQuery: (arg: Parameters<BaseQuery>[0]) => ReturnType<BaseQuery>,
): MaybePromise<QueryReturnValue<ResultType, BaseQueryError<BaseQuery>>>

/* transformResponse only available with `query`, not `queryFn` */
transformResponse?(
baseQueryReturnValue: BaseQueryResult<BaseQuery>,
meta: BaseQueryMeta<BaseQuery>,
arg: QueryArg,
): ResultType | Promise<ResultType>

/* transformErrorResponse only available with `query`, not `queryFn` */
transformErrorResponse?(
baseQueryReturnValue: BaseQueryError<BaseQuery>,
meta: BaseQueryMeta<BaseQuery>,
arg: QueryArg,
): unknown

extraOptions?: BaseQueryExtraOptions<BaseQuery>

providesTags?: ResultDescription<
TagTypes,
ResultType,
QueryArg,
BaseQueryError<BaseQuery>
>

keepUnusedDataFor?: number

onQueryStarted?(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
queryFulfilled,
getCacheEntry,
updateCachedData, // available for query endpoints only
}: QueryLifecycleApi,
): Promise<void>

onCacheEntryAdded?(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
cacheEntryRemoved,
cacheDataLoaded,
getCacheEntry,
updateCachedData, // available for query endpoints only
}: QueryCacheLifecycleApi,
): Promise<void>
}

变异端点定义

变异端点定义
export type MutationDefinition<
QueryArg,
BaseQuery extends BaseQueryFn,
TagTypes extends string,
ResultType,
ReducerPath extends string = string,
Context = Record<string, any>,
> = {
query(arg: QueryArg): BaseQueryArg<BaseQuery>

/* either `query` or `queryFn` can be present, but not both simultaneously */
queryFn(
arg: QueryArg,
api: BaseQueryApi,
extraOptions: BaseQueryExtraOptions<BaseQuery>,
baseQuery: (arg: Parameters<BaseQuery>[0]) => ReturnType<BaseQuery>,
): MaybePromise<QueryReturnValue<ResultType, BaseQueryError<BaseQuery>>>

/* transformResponse only available with `query`, not `queryFn` */
transformResponse?(
baseQueryReturnValue: BaseQueryResult<BaseQuery>,
meta: BaseQueryMeta<BaseQuery>,
arg: QueryArg,
): ResultType | Promise<ResultType>

/* transformErrorResponse only available with `query`, not `queryFn` */
transformErrorResponse?(
baseQueryReturnValue: BaseQueryError<BaseQuery>,
meta: BaseQueryMeta<BaseQuery>,
arg: QueryArg,
): unknown

extraOptions?: BaseQueryExtraOptions<BaseQuery>

invalidatesTags?: ResultDescription<TagTypes, ResultType, QueryArg>

onQueryStarted?(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
queryFulfilled,
getCacheEntry,
}: MutationLifecycleApi,
): Promise<void>

onCacheEntryAdded?(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
cacheEntryRemoved,
cacheDataLoaded,
getCacheEntry,
}: MutationCacheLifecycleApi,
): Promise<void>
}

端点如何使用

当定义一个像 getPosts 这样的键时,如下所示,重要的是要知道这个名称将从 api 中导出,并且可以在 api.endpoints.getPosts.useQuery()api.endpoints.getPosts.initiate()api.endpoints.getPosts.select() 下引用。同样的事情也适用于 mutation,但它们引用 useMutation 而不是 useQuery

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}
type PostsResponse = Post[]

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
tagTypes: ['Posts'],
endpoints: (build) => ({
getPosts: build.query<PostsResponse, void>({
query: () => 'posts',
providesTags: (result) =>
result ? result.map(({ id }) => ({ type: 'Posts', id })) : [],
}),
addPost: build.mutation<Post, Partial<Post>>({
query: (body) => ({
url: `posts`,
method: 'POST',
body,
}),
invalidatesTags: ['Posts'],
}),
}),
})

// Auto-generated hooks
export const { useGetPostsQuery, useAddPostMutation } = api

// Possible exports
export const { endpoints, reducerPath, reducer, middleware } = api
// reducerPath, reducer, middleware are only used in store configuration
// endpoints will have:
// endpoints.getPosts.initiate(), endpoints.getPosts.select(), endpoints.getPosts.useQuery()
// endpoints.addPost.initiate(), endpoints.addPost.select(), endpoints.addPost.useMutation()
// see `createApi` overview for _all exports_

extractRehydrationInfo

一个传递给每个分派的 action 的函数。如果它返回的值不是 undefined,则该返回值将用于重新水合已完成和出错的查询。

next-redux-wrapper 重新水合示例
import type { Action, PayloadAction } from '@reduxjs/toolkit'
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import { HYDRATE } from 'next-redux-wrapper'

type RootState = any // normally inferred from state

function isHydrateAction(action: Action): action is PayloadAction<RootState> {
return action.type === HYDRATE
}

export const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
extractRehydrationInfo(action, { reducerPath }): any {
if (isHydrateAction(action)) {
return action.payload[reducerPath]
}
},
endpoints: (build) => ({
// omitted
}),
})

另请参阅 服务器端渲染持久性和重新水合

tagTypes

一个字符串标签类型名称数组。指定标签类型是可选的,但您应该定义它们以便它们可以用于缓存和失效。当定义标签类型时,您将能够在配置 端点 时使用 providesTags 提供 它们,并使用 invalidatesTags 失效 它们。

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
tagTypes: ['Post', 'User'],
endpoints: (build) => ({
// ...endpoints
}),
})

reducerPath

reducerPath 是一个唯一的键,您的服务将被挂载到您的存储中。如果您在应用程序中多次调用 createApi,则每次都需要提供一个唯一的值。默认值为 'api'

apis.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

const apiOne = createApi({
reducerPath: 'apiOne',
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (builder) => ({
// ...endpoints
}),
})

const apiTwo = createApi({
reducerPath: 'apiTwo',
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (builder) => ({
// ...endpoints
}),
})

serializeQueryArgs

如果您需要出于任何原因更改缓存键的创建,则接受一个自定义函数。

默认情况下,此函数将获取查询参数,对适用的对象键进行排序,将结果字符串化,并将其与端点名称连接起来。这将根据参数 + 端点名称的组合(忽略对象键顺序)创建一个缓存键,这样,使用相同参数调用任何给定端点都会产生相同的缓存键。

keepUnusedDataFor

默认为 60 (此值为秒)。这是 RTK Query 在最后一个组件取消订阅后保留数据的时长。例如,如果您查询一个端点,然后卸载组件,然后在给定的时间范围内挂载另一个执行相同请求的组件,则将从缓存中提供最新的值。

keepUnusedDataFor 示例
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}
type PostsResponse = Post[]

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (build) => ({
getPosts: build.query<PostsResponse, void>({
query: () => 'posts',
keepUnusedDataFor: 5,
}),
}),
})

refetchOnMountOrArgChange

默认为 false。此设置允许您控制如果缓存结果已存在,RTK Query 是否只提供缓存结果,或者如果设置为 true 或者自上次成功查询结果以来已经过去了足够的时间,它是否应该 refetch

  • false - 除非缓存结果不存在,否则不会执行查询。
  • true - 当查询的新订阅者被添加时,将始终重新获取。行为与调用 refetch 回调或在操作创建者中传递 forceRefetch: true 相同。
  • number - 值为秒。如果提供了一个数字,并且缓存中存在一个现有查询,它将比较当前时间与上次完成的时间戳,并且只有在经过足够的时间后才会重新获取。

如果您在 skip: true 旁边指定此选项,则在 skip 为 false 之前,不会评估此选项。

注意

您可以在 createApi 中全局设置此选项,但您也可以通过将 refetchOnMountOrArgChange 传递给每个单独的钩子调用,或者类似地通过在调度 initiate 操作时传递 forceRefetch: true 来覆盖默认值并获得更细粒度的控制。

refetchOnFocus

默认值为 false。此设置允许您控制 RTK Query 在应用程序窗口重新获得焦点后是否尝试重新获取所有已订阅的查询。

如果您在 skip: true 旁边指定此选项,则在 skip 为 false 之前,不会评估此选项。

注意:需要调用 setupListeners

注意

您可以在 createApi 中全局设置此值,但您也可以覆盖默认值并通过将 refetchOnFocus 传递给每个单独的钩子调用或在分派 initiate 操作时获得更细粒度的控制。

如果您在手动分派查询时指定 track: false,RTK Query 将无法自动为您重新获取。

refetchOnReconnect

默认值为 false。此设置允许您控制 RTK Query 在重新获得网络连接后是否尝试重新获取所有已订阅的查询。

如果您在 skip: true 旁边指定此选项,则在 skip 为 false 之前,不会评估此选项。

注意:需要调用 setupListeners

注意

您可以在 createApi 中全局设置此值,但您也可以覆盖默认值并通过将 refetchOnReconnect 传递给每个单独的钩子调用或在分派 initiate 操作时获得更细粒度的控制。

如果您在手动分派查询时指定 track: false,RTK Query 将无法自动为您重新获取。

端点的结构

query

(如果未提供 queryFn 则为必需)

查询签名
export type query = <QueryArg>(
arg: QueryArg,
) => string | Record<string, unknown>

// with `fetchBaseQuery`
export type query = <QueryArg>(arg: QueryArg) => string | FetchArgs

query 可以是一个函数,它返回一个 string 或一个 object,该对象将传递给您的 baseQuery。如果您使用的是 fetchBaseQuery,则它可以返回 FetchArgs 中的属性的 stringobject。如果您使用自己的自定义 baseQuery,您可以根据自己的喜好自定义此行为。

查询示例
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}
type PostsResponse = Post[]

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
tagTypes: ['Post'],
endpoints: (build) => ({
getPosts: build.query<PostsResponse, void>({
query: () => 'posts',
}),
addPost: build.mutation<Post, Partial<Post>>({
query: (body) => ({
url: `posts`,
method: 'POST',
body,
}),
invalidatesTags: [{ type: 'Post', id: 'LIST' }],
}),
}),
})

queryFn

(如果未提供 query 则为必需)

可以代替 query 使用,作为内联函数,完全绕过端点的 baseQuery

使用与 baseQuery 相同的参数调用,以及提供的 baseQuery 函数本身。它应该返回一个包含 dataerror 属性的对象,或者返回一个解析为返回此类对象的 promise。

另请参阅 使用 queryFn 自定义查询

queryFn 签名
queryFn(
arg: QueryArg,
api: BaseQueryApi,
extraOptions: BaseQueryExtraOptions<BaseQuery>,
baseQuery: (arg: Parameters<BaseQuery>[0]) => ReturnType<BaseQuery>
): MaybePromise<
| {
error: BaseQueryError<BaseQuery>
data?: undefined
}
| {
error?: undefined
data: ResultType
}
>

export interface BaseQueryApi {
signal: AbortSignal
dispatch: ThunkDispatch<any, any, any>
getState: () => unknown
}

queryFn 函数参数

  • args - 查询本身被调用时提供的参数
  • api - 包含 signaldispatchgetState 属性的 BaseQueryApi 对象
    • signal - 一个 AbortSignal 对象,可用于中止 DOM 请求和/或读取请求是否已中止。
    • dispatch - 对应 Redux 存储的 store.dispatch 方法
    • getState - 一个可以被调用以访问当前存储状态的函数
  • extraOptions - 为端点提供的可选 extraOptions 属性的值
  • baseQuery - 提供给 api 本身的 baseQuery 函数
基本 queryFn 示例
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}
type PostsResponse = Post[]

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (build) => ({
getPosts: build.query<PostsResponse, void>({
query: () => 'posts',
}),
flipCoin: build.query<'heads' | 'tails', void>({
queryFn(arg, queryApi, extraOptions, baseQuery) {
const randomVal = Math.random()
if (randomVal < 0.45) {
return { data: 'heads' }
}
if (randomVal < 0.9) {
return { data: 'tails' }
}
return {
error: {
status: 500,
statusText: 'Internal Server Error',
data: "Coin landed on it's edge!",
},
}
},
}),
}),
})

transformResponse

(可选,不适用于 queryFn)

用于操作查询或变异返回的数据的函数。

在某些情况下,您可能希望在将查询返回的数据放入缓存之前对其进行操作。在这种情况下,您可以利用 transformResponse

另请参阅 使用 transformResponse 自定义查询响应

解包深度嵌套的集合
transformResponse: (response, meta, arg) =>
response.some.deeply.nested.collection

transformErrorResponse

(可选,不适用于 queryFn)

用于操作失败的查询或变异返回的数据的函数。

在某些情况下,您可能希望在将查询返回的错误放入缓存之前对其进行操作。在这种情况下,您可以利用 transformErrorResponse

另请参阅 使用 transformErrorResponse 自定义查询响应

解包深度嵌套的错误对象
transformErrorResponse: (response, meta, arg) =>
response.data.some.deeply.nested.errorObject

extraOptions

(可选)

作为第三个参数传递给提供的 baseQuery 函数

providesTags

(可选,仅适用于查询端点)

query 端点使用。确定将哪个“标签”附加到查询返回的缓存数据。期望一个标签类型字符串数组,一个包含标签类型和 ID 的对象数组,或者一个返回此类数组的函数。

  1. ['Post'] - 等效于 2
  2. [{ type: 'Post' }] - 等效于 1
  3. [{ type: 'Post', id: 1 }]
  4. (result, error, arg) => ['Post'] - 等效于 5
  5. (result, error, arg) => [{ type: 'Post' }] - 等效于 4
  6. (result, error, arg) => [{ type: 'Post', id: 1 }]

另请参阅 提供缓存数据.

providesTags 示例
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}
type PostsResponse = Post[]

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
tagTypes: ['Posts'],
endpoints: (build) => ({
getPosts: build.query<PostsResponse, void>({
query: () => 'posts',
providesTags: (result) =>
result
? [
...result.map(({ id }) => ({ type: 'Posts' as const, id })),
{ type: 'Posts', id: 'LIST' },
]
: [{ type: 'Posts', id: 'LIST' }],
}),
}),
})

invalidatesTags

(可选,仅用于 mutation 终结点)

mutation 终结点使用。确定哪些缓存数据应该重新获取或从缓存中删除。期望与 providesTags 相同的形状。

另请参阅 使缓存数据失效

invalidatesTags 示例
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}
type PostsResponse = Post[]

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
tagTypes: ['Posts'],
endpoints: (build) => ({
getPosts: build.query<PostsResponse, void>({
query: () => 'posts',
providesTags: (result) =>
result
? [
...result.map(({ id }) => ({ type: 'Posts' as const, id })),
{ type: 'Posts', id: 'LIST' },
]
: [{ type: 'Posts', id: 'LIST' }],
}),
addPost: build.mutation<Post, Partial<Post>>({
query(body) {
return {
url: `posts`,
method: 'POST',
body,
}
},
invalidatesTags: [{ type: 'Posts', id: 'LIST' }],
}),
}),
})

keepUnusedDataFor

(可选,仅适用于查询端点)

仅为此终结点覆盖 keepUnusedDataFor 的 API 范围定义。

默认为 60 (此值为秒)。这是 RTK Query 在最后一个组件取消订阅后保留数据的时长。例如,如果您查询一个端点,然后卸载组件,然后在给定的时间范围内挂载另一个执行相同请求的组件,则将从缓存中提供最新的值。

keepUnusedDataFor 示例
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}
type PostsResponse = Post[]

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (build) => ({
getPosts: build.query<PostsResponse, void>({
query: () => 'posts',
keepUnusedDataFor: 5,
}),
}),
})

serializeQueryArgs

(可选,仅适用于查询端点)

可以提供以根据查询参数返回自定义缓存键值。

这主要用于查询参数对象中传递了不可序列化值的情况,并且应该从缓存键中排除。它也可以用于终结点应该只有一个缓存条目,例如无限加载/分页实现。

createApi 版本不同,该版本只能返回字符串,此每个终结点的选项也可以返回对象、数字或布尔值。如果它返回字符串,该值将直接用作缓存键。如果它返回对象/数字/布尔值,该值将传递给内置的 defaultSerializeQueryArgs。这简化了从缓存键中排除不想包含的参数的使用情况。

serializeQueryArgs:排除值
import {
createApi,
fetchBaseQuery,
defaultSerializeQueryArgs,
} from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}

interface MyApiClient {
fetchPost: (id: string) => Promise<Post>
}

createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (build) => ({
// Example: an endpoint with an API client passed in as an argument,
// but only the item ID should be used as the cache key
getPost: build.query<Post, { id: string; client: MyApiClient }>({
queryFn: async ({ id, client }) => {
const post = await client.fetchPost(id)
return { data: post }
},
serializeQueryArgs: ({ queryArgs, endpointDefinition, endpointName }) => {
const { id } = queryArgs
// This can return a string, an object, a number, or a boolean.
// If it returns an object, number or boolean, that value
// will be serialized automatically via `defaultSerializeQueryArgs`
return { id } // omit `client` from the cache key

// Alternately, you can use `defaultSerializeQueryArgs` yourself:
// return defaultSerializeQueryArgs({
// endpointName,
// queryArgs: { id },
// endpointDefinition
// })
// Or create and return a string yourself:
// return `getPost(${id})`
},
}),
}),
})

merge

(可选,仅适用于查询端点)

可以提供将传入的响应值合并到当前缓存数据中。如果提供,将不会应用自动结构共享 - 由您负责适当地更新缓存。

由于 RTKQ 通常用新响应替换缓存条目,因此您通常需要将它与 serializeQueryArgsforceRefetch 选项一起使用以保留现有缓存条目,以便可以更新它。

由于这是用 Immer 包装的,您可以直接修改 currentCacheValue,也可以返回一个新值,但不能同时进行两者。

仅当现有 currentCacheData 不是 undefined 时才会调用 - 在第一次响应时,缓存条目将直接保存响应数据。

如果您不希望新的请求完全覆盖当前缓存值,这很有用,也许是因为您已从另一个来源手动更新了它,并且不希望这些更新丢失。

合并:分页
import {
createApi,
fetchBaseQuery,
defaultSerializeQueryArgs,
} from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}

createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (build) => ({
listItems: build.query<string[], number>({
query: (pageNumber) => `/listItems?page=${pageNumber}`,
// Only have one cache entry because the arg always maps to one string
serializeQueryArgs: ({ endpointName }) => {
return endpointName
},
// Always merge incoming data to the cache entry
merge: (currentCache, newItems) => {
currentCache.push(...newItems)
},
// Refetch when the page arg changes
forceRefetch({ currentArg, previousArg }) {
return currentArg !== previousArg
},
}),
}),
})

forceRefetch

(可选,仅适用于查询端点)

forceRefetch 签名
type forceRefetch = (params: {
currentArg: QueryArg | undefined
previousArg: QueryArg | undefined
state: RootState<any, any, string>
endpointState?: QuerySubState<any>
}) => boolean

检查端点是否应该强制重新获取,即使在通常情况下不会重新获取。这主要用于“无限滚动”/分页用例,其中 RTKQ 保持一个随着时间推移而添加的单个缓存条目,并结合 serializeQueryArgs 返回一个固定的缓存键和一个 merge 回调,每次都将传入数据添加到缓存条目中。

forceRefresh:分页
import {
createApi,
fetchBaseQuery,
defaultSerializeQueryArgs,
} from '@reduxjs/toolkit/query/react'
interface Post {
id: number
name: string
}

createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: (build) => ({
listItems: build.query<string[], number>({
query: (pageNumber) => `/listItems?page=${pageNumber}`,
// Only have one cache entry because the arg always maps to one string
serializeQueryArgs: ({ endpointName }) => {
return endpointName
},
// Always merge incoming data to the cache entry
merge: (currentCache, newItems) => {
currentCache.push(...newItems)
},
// Refetch when the page arg changes
forceRefetch({ currentArg, previousArg }) {
return currentArg !== previousArg
},
}),
}),
})

onQueryStarted

(可选)

可用于 查询变异

一个在您启动每个单独的查询或变异时调用的函数。该函数使用包含 queryFulfilled 等属性的生命周期 API 对象调用,允许在启动查询、查询成功和查询失败时(即在单个查询/变异调用的整个生命周期中)运行代码。

可以在 mutations 中用于 乐观更新

生命周期 API 属性

  • dispatch - 存储的 dispatch 方法。
  • getState - 获取存储当前状态的方法。
  • extra - 作为 thunk.extraArgument 提供给 configureStore getDefaultMiddleware 选项的 extra
  • requestId - 为查询/变异生成的唯一 ID。
  • queryFulfilled - 一个 Promise,它将解析为一个 data 属性(转换后的查询结果)和一个 meta 属性(baseQuery 返回的 meta)。如果查询失败,此 Promise 将使用错误拒绝。这允许您 await 查询完成。
  • getCacheEntry - 获取缓存条目当前值的函数。
  • updateCachedData (仅限查询端点) - 一个函数,它接受一个“配方”回调,指定如何在调用时更新相应缓存的数据。这在内部使用 immer,并且更新可以以“可变”方式编写,同时安全地生成下一个不可变状态。
Mutation onQueryStarted 签名
async function onQueryStarted(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
queryFulfilled,
getCacheEntry,
}: MutationLifecycleApi,
): Promise<void>
Query onQueryStarted 签名
async function onQueryStarted(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
queryFulfilled,
getCacheEntry,
updateCachedData, // available for query endpoints only
}: QueryLifecycleApi,
): Promise<void>
onQueryStarted 查询生命周期示例
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
import { messageCreated } from './notificationsSlice'

export interface Post {
id: number
name: string
}

const api = createApi({
baseQuery: fetchBaseQuery({
baseUrl: '/',
}),
endpoints: (build) => ({
getPost: build.query<Post, number>({
query: (id) => `post/${id}`,
async onQueryStarted(id, { dispatch, queryFulfilled }) {
// `onStart` side-effect
dispatch(messageCreated('Fetching post...'))
try {
const { data } = await queryFulfilled
// `onSuccess` side-effect
dispatch(messageCreated('Post received!'))
} catch (err) {
// `onError` side-effect
dispatch(messageCreated('Error fetching post!'))
}
},
}),
}),
})

onCacheEntryAdded

(可选)

可用于 查询变异

当添加新的缓存条目时调用此函数,即当为端点 + 查询参数组合创建新的订阅时。该函数将使用包含 cacheDataLoadedcacheDataRemoved 等属性的生命周期 API 对象调用,允许在添加缓存条目、加载缓存数据以及删除缓存条目时(即在缓存条目的整个生命周期中)运行代码。

可用于 流式更新

缓存生命周期 API 属性

  • dispatch - 存储的 dispatch 方法。
  • getState - 获取存储当前状态的方法。
  • extra - 作为 thunk.extraArgument 提供给 configureStore getDefaultMiddleware 选项的 extra
  • requestId - 为缓存条目生成的唯一 ID。
  • cacheEntryRemoved - 一个 Promise,允许您等待缓存条目从缓存中删除的时间点,方法是长时间不再在应用程序中使用/订阅,或者通过分派 api.util.resetApiState
  • cacheDataLoaded - 一个 Promise,将解析为该缓存键的第一个值。这允许您 await 直到缓存中存在实际值。
    注意:如果在任何值解析之前从缓存中删除缓存条目,此 Promise 将拒绝并抛出 new Error('Promise never resolved before cacheEntryRemoved.') 以防止内存泄漏。您可以重新抛出该错误(或根本不处理它) - 它将在 cacheEntryAdded 之外被捕获。
  • getCacheEntry - 获取缓存条目当前值的函数。
  • updateCachedData (仅查询端点) - 一个接受“配方”回调的函数,指定如何在调用时更新数据。这在内部使用 immer,并且可以在安全地生成下一个不可变状态的同时以“可变”方式编写更新。
Mutation onCacheEntryAdded 签名
async function onCacheEntryAdded(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
cacheEntryRemoved,
cacheDataLoaded,
getCacheEntry,
}: MutationCacheLifecycleApi,
): Promise<void>
Query onCacheEntryAdded 签名
async function onCacheEntryAdded(
arg: QueryArg,
{
dispatch,
getState,
extra,
requestId,
cacheEntryRemoved,
cacheDataLoaded,
getCacheEntry,
updateCachedData, // available for query endpoints only
}: QueryCacheLifecycleApi,
): Promise<void>

返回值

参见 “创建的 API” API 参考