ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Solid Query 的 queryOptions 完全指南:定义一次、处处复用的类型安全查询选项

Solid Query 的 queryOptions 完全指南:定义一次、处处复用的类型安全查询选项 Solid Query 的 queryOptions 完全指南定义一次、处处复用的类型安全查询选项【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/queryqueryOptions是 Solid Querytanstack/solid-query提供的一个类型安全辅助函数用于把一组查询选项queryKey、queryFn、staleTime等集中定义、复用并分发到useQuery、useQueries以及queryClient.query、setQueryData等命令式 API。读完本文你将掌握queryOptions的完整签名、它与 SolidJS 响应式 Accessor 的关系、其底层数据标签Data Tag类型机制以及如何在组件内覆盖选项、如何与infiniteQueryOptions配套使用从而消除查询配置重复、提升类型推断能力。什么是 queryOptions在 Solid Query 中同一份查询配置经常需要在多个地方使用组件里渲染数据、预取数据、失效后手动更新缓存……如果每个位置都手写一份{ queryKey, queryFn, ... }不仅重复而且容易出现查询键不一致导致缓存错位的隐患。queryOptions正是为解决这个问题而生的工具。它在 docs/framework/solid/reference/queryOptions.md 中定义的签名非常简单queryOptions({ queryKey, ...options, })你基本上可以把所有能传给useQuery的选项都传给queryOptions而这些选项可以在 hooks 与命令式 API如queryClient.query之间共享。运行时是透传类型上是加固从源码看queryOptions的运行时实现极其轻量——它就是一个身份函数把传入的对象原样返回// packages/solid-query/src/queryOptions.ts export function queryOptions(options: unknown) { return options }对应的单元测试也验证了这一点// packages/solid-query/src/__tests__/queryOptions.test.tsx it(should return the object received as a parameter without any modification., () { const object { queryKey: [key], queryFn: () Promise.resolve(5), } as const expect(queryOptions(object)).toBe(object) })也就是说queryOptions的全部价值都在类型层面它在编译期为你的查询配置做校验与类型推断而运行时零开销。其类型定义围绕两个关键点展开区分initialData是否存在通过UndefinedInitialDataOptions与DefinedInitialDataOptions两个类型别名以及对应的函数重载当initialData被提供时useQuery返回的data会被推断为一定存在不再是T | undefined。给queryKey打上数据标签返回类型中queryKey会被QueryKeyWithDataTagTQueryKey, TQueryFnData, TError包装使queryKey携带查询函数返回的数据类型与错误类型信息见下文数据标签机制。核心参数说明queryOptions接受一个选项对象其中queryKey为必填项其余选项与useQuery完全一致。完整的参数清单与默认值如下参数类型必填默认值说明queryKeyQueryKey✅—要为其生成选项的查询键会被哈希为稳定 hash详见 Query KeysqueryFn(context: QueryFunctionContext) PromiseTData视情况—请求数据的函数仅当未定义默认查询函数时必须提供详见 Default Query Function 与 Query Functionsenabledboolean否true设为false可禁用查询自动执行常用于 Dependent Queriesselect(data: TData) unknown否—转换/选择查询数据影响返回的data但不影响缓存内容仅在data或select引用变化时执行placeholderDataTData \| ((previousValue, previousQuery) TData)否—查询处于pending时使用的占位数据不会持久化到缓存deferStreamboolean否false服务端流式渲染时设为true会等待查询在服务端解析后再刷新流reconcilefalse \| string \| ((oldData, newData) TData)否false设为字符串按键对查询结果做协调或传入函数实现自定义协调逻辑gcTimenumber \| Infinity否5 * 60 * 1000SSR 时为Infinity未使用/非活跃缓存数据的保留毫秒数设为Infinity禁用垃圾回收最大约 24 天可通过 timeoutManager.setTimeoutProvider 突破networkModeonline \| always \| offlineFirst否online见 Network ModeinitialDataTData \| () TData否—初始缓存数据函数形式只在共享/根查询初始化时调用一次会持久化到缓存默认视为过期initialDataUpdatedAtnumber \| (() number \| undefined)否—initialData自身的最后更新时间戳metaRecordstring, unknown否—附加在缓存条目上的额外信息可在QueryFunctionContext中访问queryKeyHashFn(queryKey: QueryKey) string否—自定义查询键哈希函数refetchIntervalnumber \| false \| ((query) number \| false \| undefined)否—轮询刷新间隔毫秒函数形式接收 query 计算频率refetchIntervalInBackgroundboolean否false后台标签页是否继续轮询刷新refetchOnMountboolean \| always \| ((query) ...)否true挂载时数据过期则重新获取refetchOnWindowFocusboolean \| always \| ((query) ...)否true窗口聚焦时数据过期则重新获取refetchOnReconnectboolean \| always \| ((query) ...)否true网络重连时数据过期则重新获取retryboolean \| number \| ((failureCount, error) boolean)否客户端3服务端0失败重试策略retryOnMountboolean \| ((query) boolean)否true挂载时对含错误且无数据的查询是否重试retryDelaynumber \| ((retryAttempt, error) number)否—重试延迟如attempt Math.min(attempt 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)为指数退避staleTimenumber \| Infinity否0数据过期时间毫秒Infinity表示永不过期throwOnErrorundefined \| boolean \| ((error, query) boolean)否falseSSR 时true为true时错误在渲染阶段抛出并传播到最近的错误边界注意以上均为选项对象的字段。而在 Solid Query 中传给useQuery的往往是一个返回该对象的函数Accessor这是实现响应式的关键详见下文。在 SolidJS 中使用Accessor 与响应式选项Solid Query 的useQuery接收的是一个返回选项对象的函数AccessorQueryOptions而不是普通对象。原因在于响应式Solid Query 会在响应式作用域内追踪该函数当其依赖的 signals 变化时自动重新执行。这一点可以从useQuery的签名看出useQuery( () ({ // 选项是一个函数而非对象 queryKey, queryFn, enabled, select, // ... }), () queryClient, // 可选的 QueryClient accessor )实现上useQuery在 packages/solid-query/src/useQuery.ts 中把选项函数包进createMemo再交给useBaseQuery// packages/solid-query/src/useQuery.ts export function useQuery(options, queryClient?) { return useBaseQuery( createMemo(() options()), QueryObserver, queryClient, ) }queryOptions的返回类型同样是AccessorQueryOptions——这正是它能无缝接入useQuery(() groupOptions(1))这种写法的基础queryOptions(...)返回的 accessor 直接被useQuery当作选项函数消费响应式追踪链路保持完整。这也是 Solid Query 版queryOptions与 React Query 版本的关键差异之一在 Solid 中它返回的是函数而非普通对象。实战模式一集中定义处处复用Query Options 指南给出了最经典的用法把查询配置封装成工厂函数在组件、组合查询和命令式 API 中复用import { queryOptions } from tanstack/solid-query function groupOptions(id: number) { return queryOptions({ queryKey: [groups, id], queryFn: () fetchGroups(id), staleTime: 5 * 1000, }) } // 在组件中使用 useQuery(() groupOptions(1)) // 在组合查询中使用 useQueries(() ({ queries: [groupOptions(1), groupOptions(2)], })) // 在命令式 API 中使用 queryClient.query(groupOptions(23)) queryClient.setQueryData(groupOptions(42).queryKey, newGroups)这份配置在 hook 层与命令式 API 层共享时queryKey、queryFn、staleTime只会定义一次从根上杜绝了组件里写错 key 导致缓存对不上的常见问题。实战模式二组件级选项覆盖queryOptions返回的对象还可以在组件里展开后覆盖个别选项。最常见的模式是按组件定制select函数// 类型推断依然有效query.data 的类型是 select 的返回类型而不是 queryFn 的返回类型 const groupQuery useQuery(() ({ ...groupOptions(1), select: (data) data.groupName, }))这样既保留了集中配置的queryKey/queryFn又允许不同组件按需裁剪数据。官方指南中的类型注释明确指出此时groupQuery.data的类型会自动收窄为select的返回类型如string而不是fetchGroups的完整返回类型。数据标签机制queryKey 如何携带类型信息queryOptions最精妙之处在于它返回的对象中queryKey被打标签——即把queryFn的结果类型与错误类型编码进queryKey的类型中。这一定义位于 packages/query-core/src/types.tsexport const dataTagSymbol Symbol() export const dataTagErrorSymbol Symbol() export type DataTagTType, TValue, TError UnsetMarker TType extends AnyDataTag ? TType : TType { [dataTagSymbol]: TValue [dataTagErrorSymbol]: TError } export type QueryKeyWithDataTag TQueryKey extends QueryKey QueryKey, TQueryFnData unknown, TError DefaultError, { queryKey: DataTagTQueryKey, TQueryFnData, TError }而queryOptions的返回类型被定义为ReturnType... QueryKeyWithDataTagTQueryKey, TQueryFnData, TError见 packages/solid-query/src/queryOptions.ts。配合InferDataFromTag/InferErrorFromTag类型工具QueryClient.getQueryData(options.queryKey)、setQueryData等 API 就能从带标签的queryKey反推出正确的数据类型。queryOptions.test-d.tsx 中的类型测试完整印证了这一机制// 打上数据标签queryKey 携带 queryFn 的返回类型 it(should tag the queryKey with the result type of the QueryFn, () { const { queryKey: tagged } queryOptions({ queryKey: queryKey(), queryFn: () Promise.resolve(5), }) expectTypeOf(tagged[dataTagSymbol]).toEqualTypeOfnumber() }) // 传入带标签的 queryKey 后getQueryData 能推断出正确类型 it(should return the proper type when passed to getQueryData, () { const { queryKey: tagged } queryOptions({ queryKey: queryKey(), queryFn: () Promise.resolve(5), }) const data queryClient.getQueryData(tagged) expectTypeOf(data).toEqualTypeOfnumber | undefined() }) // setQueryData 的值也会被强类型约束 // ts-expect-error value should be a number queryClient.setQueryData(tagged, 5)同样的机制保证了useQuery(() options)中data的类型推断以及initialData存在时data被推断为非 undefined见 useQuery.test-d.tsxit(TData should be defined when passed through queryOptions, () { const options queryOptions({ queryKey: queryKey(), queryFn: () ({ wow: true }), initialData: { wow: true }, }) const { data } useQuery(() options) expectTypeOf(data).toEqualTypeOf{ wow: boolean }() })此外类型测试还验证了queryOptions会拒绝不存在的属性如拼错的stallTime并能正确推断回调参数类型、支持skipToken、支持select后的类型收窄等场景说明它是开发期捕获拼写错误与类型漂移的有效防线。与 infiniteQueryOptions 的配套使用queryOptions处理普通查询而分页/无限滚动场景对应的是 packages/solid-query/src/infiniteQueryOptions.ts 中的infiniteQueryOptions。它的结构与queryOptions完全对称同样有UndefinedInitialDataInfiniteOptions/DefinedInitialDataInfiniteOptions两个类型别名、同样的QueryKeyWithDataTag打标签逻辑区别仅在于数据被包装为InfiniteDataTQueryFnDataexport function infiniteQueryOptionsTQueryFnData, ...(options): ... QueryKeyWithDataTagTQueryKey, InfiniteDataTQueryFnData, TError两者都从 packages/solid-query/src/index.ts 统一导出并与createQueryuseQuery的别名等 API 一起构成了 Solid Query 的类型安全工具集。最佳实践小结用工厂函数封装选项function groupOptions(id) { return queryOptions({...}) }一处定义、处处复用避免查询键不一致。组件级覆盖用展开运算符useQuery(() ({ ...groupOptions(1), select: ... }))集中配置与局部定制兼顾。命令式 API 直接消费queryClient.query(options)、queryClient.setQueryData(options.queryKey, data)享受自动类型推断与标签机制带来的类型收窄。牢记 Solid 的 Accessor 语义queryOptions返回的是函数accessor它天然适配useQuery(() options)的响应式调用方式不要在组件内解构后丢失响应式追踪。不要修改返回值queryOptions运行时是身份函数原样返回传入对象因此返回值可以放心共享给多个 hook 使用。通过queryOptionsSolid Query 把查询配置从零散的样板代码提升为可复用、可类型校验的一等公民——运行时空转、编译期护航这正是它被官方推荐作为 Solid Query 应用配置组织方式的核心原因。【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/query创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表