useSuspenseQueries
概述
1function useSuspenseQueries<T extends any[], TCombinedResult = T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : [...{ [K in string | number | symbol]: GetUseSuspenseQueryResult<Tails[K]> }[]] : { [K in string | number | symbol]: GetUseSuspenseQueryResult<T[K]> }>(options: object, queryClient?: QueryClient): TCombinedResult;2function useSuspenseQueries<T extends any[], TCombinedResult = T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : [...{ [K in string | number | symbol]: GetUseSuspenseQueryResult<Tails[K]> }[]] : { [K in string | number | symbol]: GetUseSuspenseQueryResult<T[K]> }>(options: object, queryClient?: QueryClient): TCombinedResult;{ queries, combine }→TCombinedResult:useSuspenseQueries的选项与useQueries相同,但不支持顶层subscribed选项,且每个query均不能包含throwOnError、enabled或placeholderData。{ queries, combine }→TCombinedResult:useSuspenseQueries的选项与useQueries相同,但不支持顶层subscribed选项,且每个query均不能包含throwOnError、enabled或placeholderData。
调用签名
1function useSuspenseQueries<T extends any[], TCombinedResult = T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : [...{ [K in string | number | symbol]: GetUseSuspenseQueryResult<Tails[K]> }[]] : { [K in string | number | symbol]: GetUseSuspenseQueryResult<T[K]> }>(options: object, queryClient?: QueryClient): TCombinedResult;定义于:packages/preact-query/src/useSuspenseQueries.ts:407
useSuspenseQueries 的选项与 useQueries 相同,但不支持顶层 subscribed 选项,且每个 query 均不能包含 throwOnError、enabled 或 placeholderData。
类型参数
T
T extends any[]
TCombinedResult
TCombinedResult = T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : [...{ [K in string | number | symbol]: GetUseSuspenseQueryResult<Tails[K]> }[]] : { [K in string | number | symbol]: GetUseSuspenseQueryResult<T[K]> }
参数
options
在 Suspense 中运行的 queries 数组,以及一个可选的 combine 函数。
combine?
(result: T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : { [K in string | number | symbol]: GetUseSuspenseQueryResult<T[K]> }) => TCombinedResult
使用此函数将各查询结果合并为单个值。该结果将在结构上共享,以尽可能保持引用稳定性。
queries
| readonly [T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryOptions<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryOptions<Head>, GetUseSuspenseQueryOptions<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : ...[] extends [...(...)[]] ? [...(...)[]] : ... extends ... ? ... : ... : unknown[] extends T ? T : T extends UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>[] ? UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>[] : UseSuspenseQueryOptions<unknown, Error, unknown, readonly ...[]>[]]
| readonly [{ [K in string | number | symbol]: GetUseSuspenseQueryOptions<T[K]> }]
一个查询选项对象数组,其结构与 useSuspenseQuery 完全相同。
queryClient?
使用此参数传入自定义 QueryClient;否则将使用离当前组件最近的上下文中的 QueryClient。
返回值
TCombinedResult
其结构与 useQueries 相同,但对每个 query 而言,data 必然已定义,isPlaceholderData 不会出现,而 status 只能是 success 或 error(相应派生标志将被正确设置)。
注意事项:组件仅在所有查询完成加载后才会重新挂载。因此,若在全部查询完成前某查询已变为过期,则该查询将在重新挂载时再次拉取。为避免此情况,请确保设置足够高的 staleTime。取消操作不生效。
示例
若拉取失败且尚无缓存数据,则会抛出查询错误,因此 <Suspense> 外围必须包裹错误边界。后台重新拉取失败时则继续渲染缓存数据。可使用 QueryErrorResetBoundary 让用户在发生此类错误后重试:
1import { Suspense } from 'preact/compat'2import { useErrorBoundary } from 'preact/hooks'3import {4 QueryErrorResetBoundary,5 useSuspenseQueries,6} from '@tanstack/preact-query'7import type { ComponentChildren } from 'preact'8 9function Posts({ ids }: { ids: Array<number> }) {10 // Every result is guaranteed to be defined — no per-query `isPending` check needed.11 const postQueries = useSuspenseQueries({12 queries: ids.map((id) => ({13 queryKey: ['post', id],14 queryFn: () => fetchPost(id),15 })),16 })17 18 return (19 <ul>20 {postQueries.map((query) => (21 <li key={query.data.id}>{query.data.title}</li>22 ))}23 </ul>24 )25}26 27function App() {28 return (29 <QueryErrorResetBoundary>30 {({ reset }) => (31 <ErrorBoundary32 onReset={reset}33 fallbackRender={({ resetErrorBoundary }) => (34 <div>35 There was an error!36 <button onClick={() => resetErrorBoundary()}>Try again</button>37 </div>38 )}39 >40 <Suspense fallback={<h1>Loading posts...</h1>}>41 <Posts ids={[1, 2, 3]} />42 </Suspense>43 </ErrorBoundary>44 )}45 </QueryErrorResetBoundary>46 )47}48 49function ErrorBoundary({50 children,51 onReset,52 fallbackRender,53}: {54 children: ComponentChildren55 onReset: () => void56 fallbackRender: (props: {57 error: Error58 resetErrorBoundary: () => void59 }) => ComponentChildren60}) {61 const [error, resetErrorBoundary] = useErrorBoundary(() => onReset())62 63 if (error) return fallbackRender({ error, resetErrorBoundary })64 65 return children66}多个不同查询 —— 使用 useSuspenseQueries 替代多次调用 useSuspenseQuery,使它们并行拉取,而非依次挂起:
1import { Suspense } from 'preact/compat'2import { useErrorBoundary } from 'preact/hooks'3import {4 QueryErrorResetBoundary,5 useSuspenseQueries,6} from '@tanstack/preact-query'7import type { ComponentChildren } from 'preact'8 9function Dashboard() {10 const [usersQuery, teamsQuery, projectsQuery] = useSuspenseQueries({11 queries: [12 { queryKey: ['users'], queryFn: fetchUsers },13 { queryKey: ['teams'], queryFn: fetchTeams },14 { queryKey: ['projects'], queryFn: fetchProjects },15 ],16 })17 18 return (19 <div>20 <UserList users={usersQuery.data} />21 <TeamList teams={teamsQuery.data} />22 <ProjectList projects={projectsQuery.data} />23 </div>24 )25}26 27function App() {28 return (29 <QueryErrorResetBoundary>30 {({ reset }) => (31 <ErrorBoundary32 onReset={reset}33 fallbackRender={({ resetErrorBoundary }) => (34 <div>35 There was an error!36 <button onClick={() => resetErrorBoundary()}>Try again</button>37 </div>38 )}39 >40 <Suspense fallback={<h1>Loading dashboard...</h1>}>41 <Dashboard />42 </Suspense>43 </ErrorBoundary>44 )}45 </QueryErrorResetBoundary>46 )47}48 49function ErrorBoundary({50 children,51 onReset,52 fallbackRender,53}: {54 children: ComponentChildren55 onReset: () => void56 fallbackRender: (props: {57 error: Error58 resetErrorBoundary: () => void59 }) => ComponentChildren60}) {61 const [error, resetErrorBoundary] = useErrorBoundary(() => onReset())62 63 if (error) return fallbackRender({ error, resetErrorBoundary })64 65 return children66}combine 将结果合并为单个布尔值,因此 Refresh 仅在该布尔值变化时重新渲染,而非每次单个查询更新时都触发。此重载是唯一接受 combine 的版本:
1import { Suspense } from 'preact/compat'2import { useErrorBoundary } from 'preact/hooks'3import {4 QueryErrorResetBoundary,5 useSuspenseQueries,6} from '@tanstack/preact-query'7import type { ComponentChildren } from 'preact'8 9function Refresh() {10 const anyFetching = useSuspenseQueries({11 queries: [12 { queryKey: ['users'], queryFn: fetchUsers },13 { queryKey: ['teams'], queryFn: fetchTeams },14 ],15 combine: (results) => results.some((result) => result.isFetching),16 })17 18 return anyFetching ? <span>Refreshing…</span> : null19}20 21function App() {22 return (23 <QueryErrorResetBoundary>24 {({ reset }) => (25 <ErrorBoundary26 onReset={reset}27 fallbackRender={({ resetErrorBoundary }) => (28 <div>29 There was an error!30 <button onClick={() => resetErrorBoundary()}>Try again</button>31 </div>32 )}33 >34 <Suspense fallback={<h1>Loading dashboard...</h1>}>35 <Refresh />36 </Suspense>37 </ErrorBoundary>38 )}39 </QueryErrorResetBoundary>40 )41}42 43function ErrorBoundary({44 children,45 onReset,46 fallbackRender,47}: {48 children: ComponentChildren49 onReset: () => void50 fallbackRender: (props: {51 error: Error52 resetErrorBoundary: () => void53 }) => ComponentChildren54}) {55 const [error, resetErrorBoundary] = useErrorBoundary(() => onReset())56 57 if (error) return fallbackRender({ error, resetErrorBoundary })58 59 return children60}调用签名
1function useSuspenseQueries<T extends any[], TCombinedResult = T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : [...{ [K in string | number | symbol]: GetUseSuspenseQueryResult<Tails[K]> }[]] : { [K in string | number | symbol]: GetUseSuspenseQueryResult<T[K]> }>(options: object, queryClient?: QueryClient): TCombinedResult;定义于:packages/preact-query/src/useSuspenseQueries.ts:584
useSuspenseQueries 的选项与 useQueries 相同,但不支持顶层 subscribed 选项,且每个 query 均不能包含 throwOnError、enabled 或 placeholderData。
类型参数
T
T extends any[]
TCombinedResult
TCombinedResult = T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : [...{ [K in string | number | symbol]: GetUseSuspenseQueryResult<Tails[K]> }[]] : { [K in string | number | symbol]: GetUseSuspenseQueryResult<T[K]> }
参数
options
在 Suspense 中运行的 queries 数组,以及一个可选的 combine 函数。
combine?
(result: T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : { [K in string | number | symbol]: GetUseSuspenseQueryResult<T[K]> }) => TCombinedResult
使用此函数将各查询结果合并为单个值。该结果将在结构上共享,以尽可能保持引用稳定性。
queries
readonly [T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryOptions<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryOptions<Head>, GetUseSuspenseQueryOptions<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...(...)[]] extends [...] ? [..., ..., ...] : ... extends ... ? ... : ... : unknown[] extends [...Tails[]] ? [...Tails[]] : [...(...)[]] extends ...[] ? ...[] : ...[] : unknown[] extends T ? T : T extends UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>[] ? UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>[] : UseSuspenseQueryOptions<unknown, Error, unknown, readonly unknown[]>[]]
一个查询选项对象数组,其结构与 useSuspenseQuery 完全相同。
queryClient?
使用此参数传入自定义 QueryClient;否则将使用离当前组件最近的上下文中的 QueryClient。
返回值
TCombinedResult
其结构与 useQueries 相同,但对每个 query 而言,data 必然已定义,isPlaceholderData 不会出现,而 status 只能是 success 或 error(相应派生标志将被正确设置)。
注意事项:组件仅在所有查询完成加载后才会重新挂载。因此,若在全部查询完成前某查询已变为过期,则该查询将在重新挂载时再次拉取。为避免此情况,请确保设置足够高的 staleTime。取消操作不生效。
示例
若拉取失败且尚无缓存数据,则会抛出查询错误,因此 <Suspense> 外围必须包裹错误边界。后台重新拉取失败时则继续渲染缓存数据。可使用 QueryErrorResetBoundary 让用户在发生此类错误后重试:
1import { Suspense } from 'preact/compat'2import { useErrorBoundary } from 'preact/hooks'3import {4 QueryErrorResetBoundary,5 useSuspenseQueries,6} from '@tanstack/preact-query'7import type { ComponentChildren } from 'preact'8 9function Posts({ ids }: { ids: Array<number> }) {10 // Every result is guaranteed to be defined — no per-query `isPending` check needed.11 const postQueries = useSuspenseQueries({12 queries: ids.map((id) => ({13 queryKey: ['post', id],14 queryFn: () => fetchPost(id),15 })),16 })17 18 return (19 <ul>20 {postQueries.map((query) => (21 <li key={query.data.id}>{query.data.title}</li>22 ))}23 </ul>24 )25}26 27function App() {28 return (29 <QueryErrorResetBoundary>30 {({ reset }) => (31 <ErrorBoundary32 onReset={reset}33 fallbackRender={({ resetErrorBoundary }) => (34 <div>35 There was an error!36 <button onClick={() => resetErrorBoundary()}>Try again</button>37 </div>38 )}39 >40 <Suspense fallback={<h1>Loading posts...</h1>}>41 <Posts ids={[1, 2, 3]} />42 </Suspense>43 </ErrorBoundary>44 )}45 </QueryErrorResetBoundary>46 )47}48 49function ErrorBoundary({50 children,51 onReset,52 fallbackRender,53}: {54 children: ComponentChildren55 onReset: () => void56 fallbackRender: (props: {57 error: Error58 resetErrorBoundary: () => void59 }) => ComponentChildren60}) {61 const [error, resetErrorBoundary] = useErrorBoundary(() => onReset())62 63 if (error) return fallbackRender({ error, resetErrorBoundary })64 65 return children66}多个不同查询 —— 使用 useSuspenseQueries 替代多次调用 useSuspenseQuery,使它们并行拉取,而非依次挂起:
1import { Suspense } from 'preact/compat'2import { useErrorBoundary } from 'preact/hooks'3import {4 QueryErrorResetBoundary,5 useSuspenseQueries,6} from '@tanstack/preact-query'7import type { ComponentChildren } from 'preact'8 9function Dashboard() {10 const [usersQuery, teamsQuery, projectsQuery] = useSuspenseQueries({11 queries: [12 { queryKey: ['users'], queryFn: fetchUsers },13 { queryKey: ['teams'], queryFn: fetchTeams },14 { queryKey: ['projects'], queryFn: fetchProjects },15 ],16 })17 18 return (19 <div>20 <UserList users={usersQuery.data} />21 <TeamList teams={teamsQuery.data} />22 <ProjectList projects={projectsQuery.data} />23 </div>24 )25}26 27function App() {28 return (29 <QueryErrorResetBoundary>30 {({ reset }) => (31 <ErrorBoundary32 onReset={reset}33 fallbackRender={({ resetErrorBoundary }) => (34 <div>35 There was an error!36 <button onClick={() => resetErrorBoundary()}>Try again</button>37 </div>38 )}39 >40 <Suspense fallback={<h1>Loading dashboard...</h1>}>41 <Dashboard />42 </Suspense>43 </ErrorBoundary>44 )}45 </QueryErrorResetBoundary>46 )47}48 49function ErrorBoundary({50 children,51 onReset,52 fallbackRender,53}: {54 children: ComponentChildren55 onReset: () => void56 fallbackRender: (props: {57 error: Error58 resetErrorBoundary: () => void59 }) => ComponentChildren60}) {61 const [error, resetErrorBoundary] = useErrorBoundary(() => onReset())62 63 if (error) return fallbackRender({ error, resetErrorBoundary })64 65 return children66}参数
options
在 Suspense 中运行的 queries 数组,以及一个可选的 combine 函数。
combine?
(result: T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryResult<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryResult<Head>, GetUseSuspenseQueryResult<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : { [K in string | number | symbol]: GetUseSuspenseQueryResult<T[K]> }) => TCombinedResult
使用此函数将各查询结果合并为单个值。该结果将在结构上共享,以尽可能保持引用稳定性。
queries
readonly [T extends [] ? [] : T extends [Head] ? [GetUseSuspenseQueryOptions<Head>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GetUseSuspenseQueryOptions<Head>, GetUseSuspenseQueryOptions<Head>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...(...)[]] extends [...] ? [..., ..., ...] : ... extends ... ? ... : ... : unknown[] extends [...Tails[]] ? [...Tails[]] : [...(...)[]] extends ...[] ? ...[] : ...[] : unknown[] extends T ? T : T extends UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>[] ? UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>[] : UseSuspenseQueryOptions<unknown, Error, unknown, readonly unknown[]>[]]
一个查询选项对象数组,其结构与 useSuspenseQuery 完全相同。
queryClient?
使用此参数传入自定义 QueryClient;否则将使用离当前组件最近的上下文中的 QueryClient。
返回值
TCombinedResult
结构与 useQueries 相同,但对每个 query 而言,data 必定已定义,isPlaceholderData 缺失,而 status 的值为 success 或 error(相应派生标志位将被正确设置)。
注意事项:组件仅在所有查询均完成加载后才会重新挂载。因此,若在所有查询完成的这段时间内某个查询已变为过期状态,则该查询将在组件重新挂载时再次被拉取。为避免此情况,请确保设置足够高的 staleTime。取消操作不生效。