预取
预取的目标是在用户导航到页面或尝试加载一些已知内容之前获取数据。
你可能想要做这个的情况有很多,但一些非常常见的用例是:
- 用户悬停在导航元素上
- 用户悬停在列表元素上,该元素是一个链接
- 用户悬停在下一个分页按钮上
- 用户导航到一个页面,你知道树下的一些组件将需要这些数据。这样,你可以防止获取瀑布。
使用 React Hooks 进行预取
类似于 useMutation
钩子,usePrefetch
钩子不会自动运行,它返回一个"触发函数",可以用来启动行为。
它接受两个参数:第一个是你在 API 服务中定义的查询操作的键,第二个是两个可选参数的对象:
usePrefetch 签名
export type PrefetchOptions =
| { force?: boolean }
| {
ifOlderThan?: false | number;
};
usePrefetch<EndpointName extends QueryKeys<Definitions>>(
endpointName: EndpointName,
options?: PrefetchOptions
): (arg: QueryArgFrom<Definitions[EndpointName]>, options?: PrefetchOptions) => void;
自定义钩子行为
你可以在声明钩子或在调用站点时指定这些预取选项。调用站点将优先于默认值。
ifOlderThan
- (默认值:false
|number
) - 数字表示秒数- 如果指定,只有当
new Date()
与上次fulfilledTimeStamp
之间的差值大于给定值时,才会运行查询
- 如果指定,只有当
force
- 如果
force: true
,即使在缓存中存在查询,也会忽略ifOlderThan
的值并运行查询。
- 如果
触发函数行为
- 触发函数总是返回
void
。 - 如果在声明或调用站点设置了
force: true
,无论如何都会运行查询。唯一的例外是如果相同的查询已经在进行中。 - 如果没有指定选项并且查询存在于缓存中,将不会执行查询。
- 如果没有指定选项并且查询不存在于缓存中,将会执行查询。
- 假设 你在树中有一个订阅了你正在预取的相同查询的
useQuery
钩子:useQuery
将返回{isLoading: true, isFetching: true, ...rest}
- 假设 你在树中有一个订阅了你正在预取的相同查询的
- 如果指定了
ifOlderThan
但计算结果为 false 并且查询在缓存中,将不会执行查询。 - 如果指定了
ifOlderThan
并且计算结果为 true,即使存在现有的缓存条目,也会执行查询。- 假设 你在树中有一个订阅了你正在预取的相同查询的
useQuery
钩子:useQuery
将返回{isLoading: false, isFetching: true, ...rest}
- 假设 你在树中有一个订阅了你正在预取的相同查询的
usePrefetch 示例
function User() {
const prefetchUser = usePrefetch('getUser')
// 低优先级的悬停将不会触发,除非上次请求发生在35s前
// 高优先级的悬停将总是触发
return (
<div>
<button onMouseEnter={() => prefetchUser(4, { ifOlderThan: 35 })}>
低优先级
</button>
<button onMouseEnter={() => prefetchUser(4, { force: true })}>
高优先级
</button>
</div>
)
}
食谱:立即预取
在某些情况下,你可能希望立即预取一个资源。你可以用几行代码实现这个功能:
hooks/usePrefetchImmediately.ts
type EndpointNames = keyof typeof api.endpoints
export function usePrefetchImmediately<T extends EndpointNames>(
endpoint: T,
arg: Parameters<(typeof api.endpoints)[T]['initiate']>[0],
options: PrefetchOptions = {},
) {
const dispatch = useAppDispatch()
useEffect(() => {
dispatch(api.util.prefetch(endpoint, arg as any, options))
}, [])
}
// 在一个组件中
usePrefetchImmediately('getUser', 5)