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