API 切片:端点
API 切片对象将在内部有一个 endpoints
字段。此部分将您提供给 createApi
的端点名称映射到用于触发数据获取和读取该端点的缓存数据的核心 Redux 逻辑(thunks 和 selectors)。如果您正在使用 createApi
的 React 特定版本,每个端点定义还将包含该端点的自动生成的 React 钩子。
每个端点结构包含以下字段:
type EndpointLogic = {
initiate: InitiateRequestThunk
select: CreateCacheSelectorFactory
matchPending: Matcher<PendingAction>
matchFulfilled: Matcher<FulfilledAction>
matchRejected: Matcher<RejectedAction>
}
initiate
签名
type InitiateRequestThunk = StartQueryActionCreator | StartMutationActionCreator;
type StartQueryActionCreator = (
arg:any,
options?: StartQueryActionCreatorOptions
) => ThunkAction<QueryActionCreatorResult, any, any, UnknownAction>;
type StartMutationActionCreator<D extends MutationDefinition<any, any, any, any>> = (
arg: any
options?: StartMutationActionCreatorOptions
) => ThunkAction<MutationActionCreatorResult<D>, any, any, UnknownAction>;
type SubscriptionOptions = {
/**
* 自动重新获取数据的频率(以毫秒为单位)。默认为 `0`(关闭)。
*/
pollingInterval?: number;
/**
* 默认为 `false`。此设置允许您控制 RTK Query 在重新获得网络连接后是否尝试重新获取所有订阅的查询。
*
* 如果您在 `skip: true` 旁边指定了此选项,那么在 `skip` 为 false 之前,**不会评估**此选项。
*
* 注意:需要已经调用 `setupListeners`。
*/
refetchOnReconnect?: boolean;
/**
* 默认为 `false`。此设置允许您控制 RTK Query 在应用程序窗口重新获得焦点后是否尝试重新获取所有订阅的查询。
*
* 如果您在 `skip: true` 旁边指定了此选项,那么在 `skip` 为 false 之前,**不会评估**此选项。
*
* 注意:需要已经调用 `setupListeners`。
*/
refetchOnFocus?: boolean;
};
interface StartQueryActionCreatorOptions {
subscribe?: boolean;
forceRefetch?: boolean | number;
subscriptionOptions?: SubscriptionOptions;
}
interface StartMutationActionCreatorOptions {
/**
* 如果应在存储中跟踪此突变。
* 如果您只想使用 `dispatch` 手动触发此突变,并且不关心
* 结果,状态和潜在的错误被保存在存储中,您可以将此设置为 false。
* (默认为 `true`)
*/
track?: boolean;
}
描述
一个 Redux thunk 动作创建器,您可以分派它来触发数据获取查询或突变。
React Hooks 用户可能永远不需要直接使用这些,因为钩子会根据需要自动分派这些操作。
当分派一个动作创建器时,您负责在需要更新特定订阅的事件中存储对它返回的 promise 的引用。此外,一旦您的组件卸载,您必须手动取消订阅。要了解这涉及到什么,可以参见 Svelte 示例 或 React 类组件示例
示例
import { useState } from 'react'
import { useAppDispatch } from './store/hooks'
import { api } from './services/api'
function App() {
const dispatch = useAppDispatch()
const [postId, setPostId] = useState<number>(1)
useEffect(() => {
// 添加订阅
const result = dispatch(api.endpoints.getPost.initiate(postId))
// 返回 `unsubscribe` 回调,以在 `useEffect` 清理步骤中调用
return result.unsubscribe
}, [dispatch, postId])
return (
<div>
<div>Initiate query example</div>
</div>
)
}
import { useState } from 'react'
import { useAppDispatch } from './store/hooks'
import { api, Post } from './services/api'
function App() {
const dispatch = useAppDispatch()
const [newPost, setNewPost] = useState<Omit<Post, 'id'>>({ name: 'Ash' })
function handleClick() {
// 触发突变
// 在我们对突变的结果不感兴趣的情况下,`track` 属性可以设置为 `false`
dispatch(api.endpoints.addPost.initiate(newPost), { track: false })
}
return (
<div>
<div>Initiate mutation example</div>
<button onClick={handleClick}>Add post</button>
</div>
)
}
select
签名
type CreateCacheSelectorFactory =
| QueryResultSelectorFactory
| MutationResultSelectorFactory
type QueryResultSelectorFactory = (
queryArg: QueryArg | SkipToken,
) => (state: RootState) => QueryResultSelectorResult<Definition>
type MutationResultSelectorFactory<
Definition extends MutationDefinition<any, any, any, any>,
RootState,
> = (
requestId: string | SkipToken,
) => (state: RootState) => MutationSubState<Definition> & RequestStatusFlags
type SkipToken = typeof Symbol
描述
这是一个接受缓存键参数的函数,并使用给定的缓存键为此端点生成一个新的记忆化选择器,用于读取缓存数据。 生成的选择器使用 Reselect 的 createSelector
进行记忆化。
当选择突变结果而不是查询时,该函数接受一个请求 ID。
RTKQ 内部定义了一个名为 skipToken
的 Symbol
。如果 skipToken
作为查询参数传递给这些选择器,选择器将返回一个默认的未初始化状态。这可以用来避免返回一个值,如果一个给定的查询应该被禁用。
React Hooks 用户可能永远不需要直接使用这些,因为钩子会根据需要自动使用这些选择器。
每次调用 .select(someCacheKey)
都会返回一个 新的 选择器函数实例。为了使记忆化正确工作,您应该为每个缓存键创建一个给定的选择器函数,并重用该选择器函数实例,而不是每次都创建一个新的选择器实例。
示例
import { useState, useMemo } from 'react'
import { useAppDispatch, useAppSelector } from './store/hooks'
import { api } from './services/api'
function App() {
const dispatch = useAppDispatch()
const [postId, setPostId] = useState(1)
// 使用 useMemo 只在需要时调用 `.select()`。
// 每次调用都会创建一个新的选择器函数实例
const selectPost = useMemo(
() => api.endpoints.getPost.select(postId),
[postId],
)
const { data, isLoading } = useAppSelector(selectPost)
useEffect(() => {
// 添加订阅
const result = dispatch(api.endpoints.getPost.initiate(postId))
// 返回 `unsubscribe` 回调,以在清理步骤中调用
return result.unsubscribe
}, [dispatch, postId])
if (isLoading) return <div>加载帖子中...</div>
return (
<div>
<div>选择查询示例</div>
<div>帖子名称:{data.name}</div>
</div>
)
}
import { useState, useMemo } from 'react'
import { skipToken } from '@reduxjs/toolkit/query'
import { useAppDispatch, useAppSelector } from './store/hooks'
import { api } from './services/api'
function App() {
const dispatch = useAppDispatch()
const [newPost, setNewPost] = useState({ name: 'Ash' })
const [requestId, setRequestId] = useState<typeof skipToken | string>(
skipToken,
)
// 使用 useMemo 只在需要时调用 `.select(..)`。
// 每次调用都会创建一个新的选择器函数实例
const selectMutationResult = useMemo(
() => api.endpoints.addPost.select(requestId),
[requestId],
)
const { isLoading } = useAppSelector(selectMutationResult)
function handleClick() {
// 触发突变
const result = dispatch(api.endpoints.addPost.initiate(newPost))
// 存储 requestId 以在其他地方选择突变结果
setRequestId(result.requestId)
}
if (isLoading) return <div>添加帖子中...</div>
return (
<div>
<div>选择突变示例</div>
<button onClick={handleClick}>添加帖子</button>
</div>
)
}
匹配器
一组 Redux Toolkit 动作匹配实用程序,它们匹配将由此 thunk 分派的 pending
、fulfilled
和 rejected
动作。这些允许您匹配该端点的 Redux 动作,例如在 createSlice.extraReducers
或自定义中间件中。它们的实现如下:
matchPending: isAllOf(isPending(thunk), matchesEndpoint(endpoint)),
matchFulfilled: isAllOf(isFulfilled(thunk), matchesEndpoint(endpoint)),
matchRejected: isAllOf(isRejected(thunk), matchesEndpoint(endpoint)),