useQueries
1function useQueries<T extends any[], TCombinedResult = T extends [] ? [] : T extends [Head] ? [GetUseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseQueryResult<Head>, GetUseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseQueryResult<Head>, GetUseQueryResult<Head>, GetUseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : [...{ [K in string | number | symbol]: GetUseQueryResult<Tails[K]> }[]] : { [K in string | number | symbol]: GetUseQueryResult<T[K]> }>(options: object, queryClient?: QueryClient): TCombinedResult;定义于:packages/react-query/src/useQueries.ts:356
useQueries Hook 可用于拉取数量可变的查询。
queries 参数接受一个查询选项对象数组,其结构与 useQuery 大致相同——但每个查询对象均不接受顶层 subscribed 选项(另见下方 placeholderData 的另一处差异)。自定义 QueryClient 仅需提供一次,作为 useQueries 自身的顶层第二个参数,而非为每个查询单独提供。
若在查询对象数组中多次使用相同的查询键,可能导致部分数据在多个查询之间共享。为避免此情况,请考虑对查询进行去重,并将结果映射回所需的结构。
combine 选项可用于将多个查询的结果合并为单个值。该结果将在结构上共享,以尽可能保持引用稳定性。
类型参数
T
T extends any[]
TCombinedResult
TCombinedResult = T extends [] ? [] : T extends [Head] ? [GetUseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseQueryResult<Head>, GetUseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : [...{ [K in string | number | symbol]: GetUseQueryResult<Tails[K]> }[]] : { [K in string | number | symbol]: GetUseQueryResult<T[K]> }
参数
options
要执行的 queries 数组,以及可选的 combine 和 subscribed 选项。
combine?
(result: T extends [] ? [] : T extends [Head] ? [GetUseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseQueryResult<Head>, GetUseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : { [K in string | number | symbol]: GetUseQueryResult<T[K]> }) => TCombinedResult
使用该函数将多个查询的结果合并为单个值。该结果将在结构上共享,以尽可能保持引用稳定性。
queries
| readonly [T extends [] ? [] : T extends [Head] ? [GetUseQueryOptionsForUseQueries<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseQueryOptionsForUseQueries<Head>, GetUseQueryOptionsForUseQueries<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : readonly ...[] extends [...(...)[]] ? [...(...)[]] : ... extends ... ? ... : ... : readonly unknown[] extends T ? T : T extends UseQueryOptionsForUseQueries<TQueryFnData, TError, TData, TQueryKey>[] ? UseQueryOptionsForUseQueries<TQueryFnData, TError, TData, TQueryKey>[] : UseQueryOptionsForUseQueries<unknown, Error, unknown, readonly ...[]>[]]
| readonly [{ [K in string | number | symbol]: GetUseQueryOptionsForUseQueries<T[K]> }]
一个查询选项对象数组,其结构与 useQuery 大致相同——但每个查询对象均不接受 queryClient 和 subscribed(此处 subscribed 是顶层选项),且 placeholderData 接受一个 QueriesPlaceholderDataFunction,该函数接收 previousData,而 previousQuery 始终为 undefined,而非 useQuery 中的占位函数。
subscribed?
boolean
将此项设为 false,可使该观察者取消订阅查询缓存的更新。
默认值
1truequeryClient?
使用该参数提供自定义 QueryClient。否则,将使用离当前组件最近的上下文中的 QueryClient。
返回值
TCombinedResult
合并后的结果。若未提供 combine,则返回一个数组,其中包含所有查询结果,顺序与输入一致;若提供了 combine,则返回 combine 函数的返回值。
抛出异常
首个应抛出至最近错误边界的查询所对应的错误(参见 throwOnError)。在 Suspense 暂挂期间,则抛出一个 Promise。
备注
combine 函数仅在自身发生引用变化,或任一查询结果发生变化时重新执行。因此,如下方示例所示,内联的 combine 函数会在每次渲染时执行——请将其包裹在 useCallback 中,或提取为一个无依赖的稳定函数引用,以避免不必要的重复执行。
与 useQuery 不同,useQueries 无法从其兄弟 queryFn 中推断 内联 select 的 data 参数。由于 useQueries 是一次性推断整个 queries 数组的类型,因此内联编写的查询对象中的 select 参数无法通过该对象自身的 queryFn 进行上下文类型推导,最终会回退为 unknown —— 这是 TypeScript 的一个已知限制(known TypeScript limitation)。请显式标注 select 参数类型,或使用 queryOptions 定义查询,后者可在查询对象传入 useQueries 之前,于单个对象内完成类型解析,从而规避该问题——详见下方示例。同样的限制也适用于 useSuspenseQueries。
placeholderData 在此处同样受支持,但与 useQuery 不同,它不会接收先前渲染过的查询信息,因为不同渲染周期中查询的数量可能不同。
示例
1import { useQueries } from '@tanstack/react-query'2 3function Posts({ ids }: { ids: Array<number> }) {4 const postQueries = useQueries({5 queries: ids.map((id) => ({6 queryKey: ['post', id],7 queryFn: () => fetchPost(id),8 staleTime: Infinity,9 })),10 })11 12 return (13 <ul>14 {postQueries.map((query, index) => {15 if (query.isPending) return <li key={ids[index]}>Loading...</li>16 if (query.isError) return <li key={ids[index]}>Error: {query.error.message}</li>17 return <li key={ids[index]}>{query.data.title}</li>18 })}19 </ul>20 )21}将结果合并为单个值:
1import { useQueries } from '@tanstack/react-query'2 3function Posts({ ids }: { ids: Array<number> }) {4 const { data, isPending, isError } = useQueries({5 queries: ids.map((id) => ({6 queryKey: ['post', id],7 queryFn: () => fetchPost(id),8 })),9 combine: (postQueries) => {10 return {11 data: postQueries.map((query) => query.data),12 isPending: postQueries.some((query) => query.isPending),13 isError: postQueries.some((query) => query.isError),14 }15 },16 })17 18 if (isPending) return 'Loading...'19 if (isError) return 'Error loading posts'20 21 return (22 <ul>23 {data.map((post) => (24 <li key={post?.id}>{post?.title}</li>25 ))}26 </ul>27 )28}通过 queryOptions 对 select 进行类型标注。注意:对 queryOptions 结果进行展开并内联覆盖 select 仍会回退为 unknown —— 请将展开操作再次包裹在 queryOptions 中,确保覆盖逻辑在传入 useQueries 前完成类型解析:
1import { queryOptions, useQueries } from '@tanstack/react-query'2 3const postOptions = (id: number) =>4 queryOptions({5 queryKey: ['post', id],6 queryFn: () => fetchPost(id),7 })8 9function PostTitle({ id }: { id: number }) {10 const [{ data: broken }] = useQueries({11 queries: [12 {13 ...postOptions(id),14 // ❌ `data` is `unknown` here15 select: (data) => data.title,16 },17 ],18 })19 20 const [{ data: fixed }] = useQueries({21 queries: [22 queryOptions({23 ...postOptions(id),24 // ✅ `data` is `Post`25 select: (data) => data.title,26 }),27 ],28 })29 30 return <h1>{fixed}</h1>31}