API 分片: React Hooks
Hooks 概览
RTK Query 的核心 createApi
方法是与UI无关的,就像 Redux 核心库和 Redux Toolkit 一样。它们都是可以在任何地方使用的纯 JS 逻辑。因此,如果你从 '@reduxjs/toolkit/query'
导入 createApi
,它不会包含任何特定的 UI 集成。
然而,RTK Query 也提供了为每个端点自动生成 React hooks 的能力。由于这特别依赖于 React 本身,RTK Query 提供了一个额外的入口点,暴露了一个包含该功能的自定义版本的 createApi
:
import { createApi } from '@reduxjs/toolkit/query/react'
如果你使用了 React 特定版本的 createApi
,生成的 api
分片结构也将包含一组 React hooks。主要的端点 hooks 可用作 api.endpoints[endpointName].useQuery
、api.endpoints[endpointName].useMutation
和 api.endpoints[endpointName].useInfiniteQuery
,与你定义该端点的方式相匹配。
生成的 Hook 名称
相同的 hooks 也被添加到 api
对象本身,并根据端点名称和查询/修改类型获得自动生成的名称。
例如,如果你有用于 getPosts
和 updatePost
的端点,以下选项将可用:
// 附加到端点定义的 hooks
const { data } = api.endpoints.getPosts.useQuery()
const [updatePost, { data }] = api.endpoints.updatePost.useMutation()
// 相同的 hooks,但具有唯一的名称并附加到 API 分片对象
const { data } = api.useGetPostsQuery()
const [updatePost, { data }] = api.useUpdatePostMutation()
通用格式是 use(端点名称)(Query|Mutation|InfiniteQuery)
- 前缀是 use
,端点名称的第一个字母大写,然后根据类型附加 Query
或 Mutation
或 InfiniteQuery
。
可用的 Hooks
RTK Query 提供了更多高级用例的额外 hooks,尽管并非所有都直接生成在 api
对象上。
大多数 hooks 是按端点生成的。
在 React 特定版本的 createApi
中生成的 hooks 的完整列表如下:
- 端点特定的,在
api
对象上生成唯一名称,在端点对象上生成通用名称:useQuery
(所有标准查询)useMutation
(所有修改)useInfiniteQuery
(仅无限查询)useLazyQuery
(所有标准查询)
- 端点特定的,仅在端点对象上生成通用名称:
- 与端点无关的,在
api
对象上生成:
对于上述示例,api 生成的 hooks 的完整集合如下所示:
/* 附加到 `getPosts` 查询端点定义的 hooks */
api.endpoints.getPosts.useQuery(arg, options)
api.endpoints.getPosts.useQueryState(arg, options)
api.endpoints.getPosts.useQuerySubscription(arg, options)
api.endpoints.getPosts.useLazyQuery(options)
api.endpoints.getPosts.useLazyQuerySubscription(options)
/* 附加到 `getManyPosts` 无限查询端点定义的 hooks */
api.endpoints.getManyPosts.useInfiniteQuery(arg, options)
api.endpoints.getManyPosts.useInfiniteQueryState(arg, options)
api.endpoints.getManyPosts.useInfiniteQuerySubscription(arg, options)
/* 附加到 `updatePost` 修改端点定义的 hooks */
api.endpoints.updatePost.useMutation(options)
/* 附加到 `api` 对象的 hooks */
// 与 api.endpoints.getPosts.useQuery 相同
api.useGetPostsQuery(arg, options)
// 与 api.endpoints.getPosts.useLazyQuery 相同
api.useLazyGetPostsQuery(arg, options)
// 与 api.endpoints.updatePost.useMutation 相同
api.useUpdatePostMutation(arg, options)
// 与 api.endpoints.getManyPosts.useInfiniteQuery 相同
api.useGetManyPostsInfiniteQuery(arg, options)
// 通用,用于任何端点
api.usePrefetch(endpointName, options)
功能比较
提供的 hooks 在一定程度上有功能重叠,以便为给定情况提供优化的选项。下表提供了每个 hook 的核心功能比较。
主要 Hooks
这些 hooks 是你在 React 组件中与 RTK Query 交互的主要方法。它们封装了大多数数据获取和更新用例所需的所有逻辑和选项。
useQuery
const useQueryResult = api.endpoints.getPosts.useQuery(arg, options)
// 或
const useQueryResult = api.useGetPostsQuery(arg, options)
一个 React 钩子,它会自动触发从端点获取数据的请求,将组件'订阅'到缓存数据,并从 Redux 存储中读取请求状态和缓存数据。随着加载状态的变化和数据的可用性,组件将重新渲染。
查询参数被用作缓存键。改变查询参数将告诉钩子如果缓存中不存在数据则重新获取数据,一旦数据可用,钩子将返回该查询参数的数据。
这个钩子将 useQueryState
和 useQuerySubscription
的功能结合在一起,预期在大多数情况下使用。
特性
- 根据钩子参数和是否存在 缓存数据,默认自动触发获取数据的请求
- 将组件'订阅'以在存储中保持缓存数据,并在组件卸载时'取消订阅'
- 接受轮询/重新获取选项,当满足相应条件时触发自动重新获取
- 从 Redux 存储中返回最新的请求状态和缓存数据
- 随着请求状态的变化和数据的可用性重新渲染
useQuery
签名
type UseQuery = (
arg: any | SkipToken,
options?: UseQueryOptions,
) => UseQueryResult
type UseQueryOptions = {
pollingInterval?: number
skipPollingIfUnfocused?: boolean
refetchOnReconnect?: boolean
refetchOnFocus?: boolean
skip?: boolean
refetchOnMountOrArgChange?: boolean | number
selectFromResult?: (result: UseQueryStateDefaultResult) => any
}
type UseQueryResult<T> = {
// 基本查询状态
// 传递给查询的参数
originalArgs?: unknown
// 最新返回的结果,无论 hook 参数如何,如果存在
data?: T
// 当前 hook 参数的最新返回结果,如果存在
currentData?: T
// 错误结果,如果存在
error?: unknown
// 由 RTK Query 生成的字符串
requestId?: string
// 查询的端点名称
endpointName?: string
// 查询启动的时间戳
startedTimeStamp?: number
// 查询完成的时间戳
fulfilledTimeStamp?: number
// 派生的请求状态布尔值
// 查询尚未开始。
isUninitialized: boolean
// 查询正在首次加载。尚无数据。
isLoading: boolean
// 查询正在获取,但可能有来自早期请求的数据。
isFetching: boolean
// 查询有来自成功加载的数据。
isSuccess: boolean
// 查询当前处于“错误”状态。
isError: boolean
// 强制重新获取查询的函数 - 返回一个带有附加方法的 Promise
refetch: () => QueryActionCreatorResult
}
- 参数
arg
: 用于构建查询本身的查询参数,以及作为查询的缓存键。 你也可以在这里传递skipToken
作为跳过查询的替代方法,请参阅 skipTokenoptions
: 一组控制 hook 获取行为的选项
- 返回
- 一个查询结果对象,包含当前的加载状态、API 调用返回的实际数据或错误、请求的元数据以及重新获取数据的函数。可以使用
selectFromResult
进行自定义
- 一个查询结果对象,包含当前的加载状态、API 调用返回的实际数据或错误、请求的元数据以及重新获取数据的函数。可以使用
skipToken
可以传递给 useQuery
,useQueryState
或 useQuerySubscription
作为查询参数,效果与在查询选项中设置 skip: true
相同。
对于当 arg
为 undefined
时应跳过查询的场景非常有用,
并且 TypeScript 会因为不允许将 arg
传入为 undefined
而抱怨,
例如
useSomeQuery(arg, { skip: !!arg })
useSomeQuery(arg ?? skipToken)
如果直接传递给查询或突变选择器,那么该选择器将始终 返回一个未初始化的状态。
另请参阅 使用 TypeScript 跳过查询
useMutation
const useMutationResult = api.endpoints.updatePost.useMutation(options)
// 或
const useMutationResult = api.useUpdatePostMutation(options)
一个React钩子,它让你触发给定端点的更新请求,并让组件订阅从Redux存储中读取请求状态。当加载状态改变时,组件将重新渲染。
特性
- 手动控制触发请求以更改服务器上的数据或可能使缓存失效
- '订阅' 组件以保持缓存数据在存储中,并在组件卸载时 '取消订阅'
- 从Redux存储中返回最新的请求状态和缓存数据
- 当请求状态改变和数据变得可用时重新渲染
useMutation
签名
type UseMutation = (
options?: UseMutationStateOptions,
) => [UseMutationTrigger, UseMutationResult | SelectedUseMutationResult]
type UseMutationStateOptions = {
// 用于确定 `UseMutationResult` 内容的方法
selectFromResult?: (result: UseMutationStateDefaultResult) => any
// 用于启用具有相同键的 hook 实例之间共享结果的字符串
fixedCacheKey?: string
}
type UseMutationTrigger<T> = (arg: any) => Promise<
{ data: T } | { error: BaseQueryError | SerializedError }
> & {
requestId: string // 由 RTK Query 生成的字符串
abort: () => void // 取消修改 promise 的方法
unwrap: () => Promise<T> // 解包修改调用并提供原始响应/错误的方法
reset: () => void // 手动取消订阅修改调用并将结果重置为未初始化状态的方法
}
type UseMutationResult<T> = {
// 基本查询状态
// 传递给最新修改调用的参数。如果使用 `fixedCacheKey` 选项,则不可用
originalArgs?: unknown
// 返回结果,如果存在
data?: T
// 错误结果,如果存在
error?: unknown
// 修改的端点 名称
endpointName?: string
// 修改完成的时间戳
fulfilledTimeStamp?: number
// 派生的请求状态布尔值
// 修改尚未触发
isUninitialized: boolean
// 修改已触发并等待响应
isLoading: boolean
// 修改有来自成功调用的数据
isSuccess: boolean
// 修改当前处于“错误”状态
isError: boolean
// 最新修改启动的时间戳
startedTimeStamp?: number
// 手动取消订阅修改调用并将结果重置为未初始化状态的方法
reset: () => void
}
生成的 UseMutation
hook 将默认在触发回调后导致组件重新渲染,因为它会影响结果的属性。如果你想调用触发器但不关心使用 hook 订阅结果,可以使用 selectFromResult
选项来限制 hook 关心的属性。
返回一个完全空的对象将意味着任何单个修改调用最多只会导致一次重新渲染,例如
selectFromResult: () => ({})
-
参数
options
: 一组控制 hook 订阅行为的选项:selectFromResult
: 一个回调,可用于自定义作为元组第二项返回的修改结果fixedCacheKey
: 一个可选字符串,用于启用 hook 实例之间共享结果
-
返回: 一个包含以下内容的元组:
trigger
: 一个函数,根据提供的参数触发数据更新。触发函数返回一个带有上述属性的 promise,可用于处理 promise 的行为mutationState
: 一个查询状态对象,包含当前的加载状态和请求的元数据,或selectFromResult
选项返回的值(如果适用)。 此外,此对象将包含- 一个
reset
方法,用于将 hook 重置回其原始状态并从缓存中删除当前结果 - 一个
originalArgs
属性,包含传递给trigger
函数的最后一个调用的参数。
- 一个
useInfiniteQuery
const useQueryResult = api.endpoints.getManyPosts.useInfiniteQuery(arg, options)
// 或
const useQueryResult = api.useGetManyPostsInfiniteQuery(arg, options)
useInfiniteQuery
签名
type UseInfiniteQuery = (
arg: any | SkipToken,
options?: UseQueryOptions,
) => UseInfiniteQueryResult
type InfiniteData<Data, PageParam> = {
pages: Array<Data>
pageParams: Array<PageParam>
}
type UseInfiniteQueryOptions = {
pollingInterval?: number
skipPollingIfUnfocused?: boolean
refetchOnReconnect?: boolean
refetchOnFocus?: boolean
skip?: boolean
refetchOnMountOrArgChange?: boolean | number
selectFromResult?: (result: UseQueryStateDefaultResult) => any
initialPageParam?: PageParam
}
type UseInfiniteQueryResult<Data, PageParam> = {
// 基本查询状态
// 传递给查询的参数
originalArgs?: unknown
// 最新返回的结果,无论 hook 参数如何,如果存在
data?: InfiniteData<Data, PageParam>
// 当前 hook 参数的最新返回结果,如果存在
currentData?: InfiniteData<Data, PageParam>
// 错误结果,如果存在
error?: unknown
// 由 RTK Query 生成的字符串
requestId?: string
// 查询的端点名称
endpointName?: string
// 查询启动的时间戳
startedTimeStamp?: number
// 查询完成的时间戳
fulfilledTimeStamp?: number
// 派生的请求状态布尔值
// 查询尚未开始。
isUninitialized: boolean
// 查询正在首次加载。尚无数据。
isLoading: boolean
// 查询正在获取,但可能有来自早期请求的数据。
isFetching: boolean
// 查询有来自成功加载的数据。
isSuccess: boolean
// 查询当前处于“错误”状态。
isError: boolean
// 无限查询页面的派生请求状态布尔值
// 查询前进时有另一个页面可用
hasNextPage: boolean
// 查询后退时有另一个页面可用
hasPreviousPage: boolean
// 当前进行中的获取是下一页
isFetchingNextPage: boolean
// 当前进行中的获取是上一页
isFetchingPreviousPage: boolean
// 获取下一页时发生的当前错误
isFetchNextPageError: boolean
// 获取上一页时发生的当前错误
isFetchPreviousPageError: boolean
// 强制重新获取查询的函数 - 返回一个带有附加方法的 Promise
refetch: () => InfiniteQueryActionCreatorResult
// 根据当前缓存触发下一页的获取
fetchNextPage: () => InfiniteQueryActionCreatorResult
// 根据当前缓存触发上一页的获取
fetchPreviousPage: () => InfiniteQueryActionCreatorResult
}
- 参数
arg
: 用于构建查询本身的查询参数,以及作为查询的缓存键。 你也可以在这里传递skipToken
作为跳过查询的替代方法,请参阅 skipTokenoptions
: 一组控制 hook 获取行为的选项
- 返回
- 一个查询结果对象,包含当前的加载状态、API 调用返回的实际数据或错误、请求的元数据以及重新获取数据的函数。可以使用
selectFromResult
进行自定义
- 一个查询结果对象,包含当前的加载状态、API 调用返回的实际数据或错误、请求的元数据以及重新获取数据的函数。可以使用
次要 Hooks
这些 hooks 在你的应用程序中有特定的额外用例,但可能不会经常使用。
useLazyQuery
const [trigger, result, lastPromiseInfo] =
api.endpoints.getPosts.useLazyQuery(options)
// 或
const [trigger, result, lastPromiseInfo] = api.useLazyGetPostsQuery(options)
一个类似于 useQuery
的 React 钩子,但对数据获取的时间有手动控制。
这个钩子包含了 useLazyQuerySubscription
的功能。
特性
- 手动控制触发请求以检索数据
- '订阅' 组件以保持缓存数据在存储中,并在组件卸载时 '取消订阅'
- 从 Redux 存储中返回最新的请求状态和缓存数据
- 随着请求状态的变化和数据的可用性重新渲染
- 接受轮询/重新获取选项,当满足相应条件并且至少手动调用了一次获取时,触发自动重新获取
注意
当从 LazyQuery 返回的触发函数被调用时,即使有缓存数据,它总是启动一个新的请求到服务器。如果你希望它立即返回一个缓存值(如果存在的话),请将 preferCacheValue
(函数的第二个参数)设置为 true
。
useLazyQuery
签名
type UseLazyQuery = (
options?: UseLazyQueryOptions
) => [UseLazyQueryTrigger, UseLazyQueryStateResult, UseLazyQueryLastPromiseInfo]
type UseLazyQueryOptions = {
pollingInterval?: number
skipPollingIfUnfocused?: boolean
refetchOnReconnect?: boolean
refetchOnFocus?: boolean
selectFromResult?: (result: UseQueryStateDefaultResult) => any
}
type UseLazyQueryTrigger<T> = (arg: any, preferCacheValue?: boolean) => Promise<
QueryResultSelectorResult
> & {
// 提供给查询的参数
arg: unknown
// 由 RTK Query 生成的字符串
requestId: string
// 用于查询订阅的值
subscriptionOptions: SubscriptionOptions
// 取消查询 promise 的方法
abort: () => void
// 解包查询调用并提供原始响应/错误的方法
unwrap: () => Promise<T>
// 用于手动取消订阅查询结果的方法
unsubscribe: () => void
// 用于重新运行查询的方法。在大多数情况下,使用懒查询时,你永远不会使用它,应该更喜欢再次调用触发器。
refetch: () => void
// 用于更新订阅选项的方法(例如轮询间隔)
updateSubscriptionOptions: (options: SubscriptionOptions) () => void
}
type UseLazyQueryStateResult<T> = {
// 基本查询状态
// 传递给查询的参数
originalArgs?: unknown
// 最新返回的结果,无论 hook 参数如何,如果存在
data?: T
// 当前 hook 参数的最新返回结果,如果存在
currentData?: T
// 错误结果,如果存在
error?: unknown
// 由 RTK Query 生成的字符串
requestId?: string
// 查询的端点名称
endpointName?: string
// 查询启动的时间戳
startedTimeStamp?: number
// 查询完成的时间戳
fulfilledTimeStamp?: number
// 派生的请求状态布尔值
// 查询尚未开始。
isUninitialized: boolean
// 查询正在首次加载。尚无数据。
isLoading: boolean
// 查询正在获取,但可能有来自早期请求的数据。
isFetching: boolean
// 查询有来自成功加载的数据。
isSuccess: boolean
// 查询当前处于“错误”状态。
isError: boolean
}
type UseLazyQueryLastPromiseInfo = {
lastArg: any
}
-
参数
options
: 一组控制 hook 获取行为和返回结果值的选项。影响获取行为的选项只有在懒查询至少触发一次后才会生效。
-
返回: 一个包含以下内容的元组:
trigger
: 一个函数,在调用时获取端点的相应数据result
: 一个查询结果对象,包含当前的加载状态、API 调用返回的实际数据或错误以及请求的元数据。可以使用selectFromResult
进行自定义lastPromiseInfo
: 一个包含最后一个调用触发函数的参数的对象
usePrefetch
const prefetchCallback = api.usePrefetch(endpointName, options)
一个 React hook,可用于提前获取数据。
功能
- 手动控制触发请求以检索数据
签名
type UsePrefetch = (
endpointName: string,
options?: UsePrefetchOptions,
) => PrefetchCallback
type UsePrefetchOptions =
| {
// 如果指定,只有在 `new Date()` 和最后一个 `fulfilledTimeStamp` 之间的差异大于给定值(以秒为单位)时才运行查询
ifOlderThan?: false | number
}
| {
// 如果 `force: true`,它将忽略 `ifOlderThan` 值(如果已设置),并且即使存在于缓存中,查询也会运行。
force?: boolean
}
type PrefetchCallback = (arg: any, options?: UsePrefetchOptions) => void
-
参数
endpointName
: 要预获取数据的端点名称options
: 一组控制预获取请求是否应发生的选项
-
返回
- 一个
prefetch
回调,在调用时,将启动获取提供的端点的数据
- 一个
实现 Hooks
这些 hooks 作为主要 hooks 的实现细节存在。它们在少数情况下可能有用,但你通常应该在应用中使用主要 hooks。
useQueryState
const useQueryStateResult = api.endpoints.getPosts.useQueryState(arg, options)
一个React钩子,从Redux存储中读取请求状态和缓存数据。当加载状态改变和数据变得可用时,组件将重新渲染。
注意,这个钩子不会触发获取新数据。对于这种用例,请查看 useQuery
或 useQuerySubscription
。
特性
- 从Redux存储中返回最新的请求状态和缓存数据
- 当请求状态改变和数据变得可用时重新渲染
useQueryState
签名
type UseQueryState = (
arg: any | SkipToken,
options?: UseQueryStateOptions,
) => UseQueryStateResult | SelectedQueryStateResult
type UseQueryStateOptions = {
skip?: boolean
selectFromResult?: (result: UseQueryStateDefaultResult) => any
}
type UseQueryStateResult<T> = {
// 基本查询状态
// 传递给查询的参数
originalArgs?: unknown
// 最新返回的结果,无论 hook 参数如何,如果存在
data?: T
// 当前 hook 参数的最新返回结果,如果存在
currentData?: T
// 错误结果,如果存在
error?: unknown
// 由 RTK Query 生成的字符串
requestId?: string
// 查询的端点名称
endpointName?: string
// 查询启动的时间戳
startedTimeStamp?: number
// 查询完成的时间戳
fulfilledTimeStamp?: number
// 派生的请求状态布尔值
// 查询尚未开始。
isUninitialized: boolean
// 查询正在首次加载。尚无数据。
isLoading: boolean
// 查询正在获取,但可能有来自早期请求的数据。
isFetching: boolean
// 查询有来自成功加载的数据。
isSuccess: boolean
// 查询当前处于“错误”状态。
isError: boolean
}
-
参数
arg
: 传递给端点中定义的查询的参数。 你也可以在这里传递skipToken
作为跳过选择的替代方法,请参阅 skipTokenoptions
: 一组控制 hook 返回值的选项
-
返回
- 一个查询结果对象,包含当前的加载状态、API 调用返回的实际数据或错误以及请求的元数据。可以使用
selectFromResult
进行自定义
- 一个查询结果对象,包含当前的加载状态、API 调用返回的实际数据或错误以及请求的元数据。可以使用
useQuerySubscription
const { refetch } = api.endpoints.getPosts.useQuerySubscription(arg, options)
一个 React 钩子,它自动触发从端点获取数据,并将组件 '订阅' 到缓存数据。
查询参数被用作缓存键。改变查询参数将告诉钩子如果数据在缓存中不存在则重新获取数据。
注意,这个钩子不返回请求状态或缓存数据。对于这种用例,请查看 useQuery
或 useQueryState
。
特性
- 根据钩子参数和是否存在缓存数据,默认自动触发请求以检索数据
- '订阅' 组件以保持缓存数据在存储中,并在组件卸载时 '取消订阅'
- 接受轮询/重新获取选项,当满足相应条件时触发自动重新获取
useQuerySubscription
签名
type UseQuerySubscription = (
arg: any | SkipToken,
options?: UseQuerySubscriptionOptions,
) => UseQuerySubscriptionResult
type UseQuerySubscriptionOptions = {
skip?: boolean
refetchOnMountOrArgChange?: boolean | number
pollingInterval?: number
skipPollingIfUnfocused?: boolean
refetchOnReconnect?: boolean
refetchOnFocus?: boolean
}
type UseQuerySubscriptionResult = {
refetch: () => void // 强制重新获取查询的函数
}
-
参数
arg
: 传递给端点中定义的查询的参数。 你也可以在这里传递skipToken
作为跳过查询的替代方法,请参阅 skipTokenoptions
: 一组控制 hook 获取行为的 选项
-
返回
- 一个包含重新获取数据函数的对象
useInfiniteQueryState
const useInfiniteQueryStateResult =
api.endpoints.getManyPosts.useInfiniteQueryState(arg, options)
useInfiniteQuerySubscription
const useInfiniteQuerySubscriptionResult =
api.endpoints.getManyPosts.useInfiniteQuerySubscription(arg, options)
useLazyQuerySubscription
const [trigger, lastArg] =
api.endpoints.getPosts.useLazyQuerySubscription(options)
一个类似于 useQuerySubscription
的 React 钩子,但对数据获取的时间有手动控制。
注意,这个钩子不返回请求状态或缓存数据。对于这种用例,请查看 useLazyQuery
。
特性
- 手动控制触发请求以检索数据
- '订阅' 组件以保持缓存数据在存储中,并在组件卸载时 '取消订阅'
- 接受轮询/重新获取选项,当满足相应条件并且至少手动调用了一次获取时,触发自动重新获取
useLazyQuerySubscription
签名
type UseLazyQuerySubscription = (
options?: UseLazyQuerySubscriptionOptions,
) => [UseLazyQuerySubscriptionTrigger, LastArg]
type UseLazyQuerySubscriptionOptions = {
pollingInterval?: number
skipPollingIfUnfocused?: boolean
refetchOnReconnect?: boolean
refetchOnFocus?: boolean
}
type UseLazyQuerySubscriptionTrigger = (
arg: any,
preferCacheValue?: boolean,
) => void
-
参数
options
: 一组控制 hook 获取行为的选项。选项只有在懒查询至少触发一次后才会生效。
-
返回: 一个包含以下内容的元组:
trigger
: 一个函数,在调用时获取端点的相应数据lastArg
: 最后一个调用触发函数的参数