TanStack Lit Query 的 Accessor 类型让查询选项同时支持静态值与响应式 Getter【免费下载链接】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本文围绕tanstack/lit-query的核心类型别名AccessorT展开它是 Lit Query 全部控制器 API 的响应式入口允许把查询/变更mutation选项以静态对象或零参 getter 两种形式传入。读完本文你将理解Accessor的定义与readAccessor读取机制、它在控制器生命周期中何时被求值的底层实现以及如何在 Lit 组件中正确编写静态 key 与依赖宿主状态的响应式 key。1. Accessor 的定义T | (() T)Accessor是 packages/lit-query/src/accessor.ts 中定义的类型别名type AccessorT T | () T;它的语义在源码注释中已经写得很明确accessor.ts#L1-L12A value that can be passed directly or read from a zero-argument getter. Lit Query APIs read function accessors during host updates, so the getter can depend on reactive host state.也就是说AccessorT接受两种形式静态值直接传T本身例如[todos]这样的查询 key 或完整选项对象零参 getter传一个() T函数getter 在宿主Lit 元素更新时被重新求值因此它可以闭包引用this.userId等响应式宿主状态。类型参数只有一个T表示最终被读出来的值的类型。文档给出的最小示例docs/framework/lit/reference/type-aliases/Accessor.mdconst staticKey: Accessorreadonly unknown[] [todos] const reactiveKey: Accessorreadonly unknown[] () [todos, this.userId]两者类型完全兼容——这正是该类型别名存在的全部意义让同一份 API 签名同时接纳常量配置与随宿主状态变化的配置而不需要拆成两个函数。2. 读取机制readAccessorAccessor只是类型约定真正的求值逻辑由同文件中的readAccessor函数完成accessor.ts#L15-L17export function readAccessorT(value: AccessorT): T { return typeof value function ? (value as () T)() : value }逻辑极其简洁若传入的是函数则调用它取返回值否则原样返回。整个 lit-query 包中凡是把Accessor解析为真实值的地方都走这一个函数。从源码结构看全部调用点分布在各个控制器与状态钩子中调用点解析的对象createQueryController.ts#L302readAccessor(this.options)再交给client.defaultQueryOptions(...)createMutationController.ts#L294readAccessor(this.options)再交给client.defaultMutationOptions(...)createInfiniteQueryController.ts#L342无限查询选项createQueriesController.ts#L296-L297双层解析readAccessor(optionsAccessor)后再readAccessor(resolvedOptions.queries)useIsFetching.ts#L112、useIsMutating.ts#L112过滤器条件readAccessor(this.filters)其中createQueriesController特别值得注意它把queries数组本身也定义成了Accessor因此在 types.ts#L74-L77 中QueriesControllerOptions.queries的类型是AccessorArray...——即查询列表也可以随宿主状态整体变化。3. 求值时机静态选项与函数选项的两条路径Accessor不是简单的延迟取值它在控制器内部对应两条明显不同的初始化路径。以 createQueryController.ts 为例构造函数中createQueryController.ts#L109-L133constructor(host, options, queryClient?) { const initialClient queryClient super(host, createPendingQueryResult(), queryClient) this.options options if (!initialClient) { return } if (typeof options function) { return // 函数 accessor此刻不创建 observer } const defaulted this.defaultOptions(initialClient) const observer new QueryObserver(initialClient, defaulted) ... }可以推断出两条路径的行为差异静态选项构造时立即readAccessor求值、创建QueryObserver并计算乐观结果挂载后马上订阅函数选项构造时直接返回把求值推迟到宿主更新阶段——QueryController.onHostUpdate()createQueryController.ts#L153-L159protected onHostUpdate(): void { if (typeof this.options ! function) { return // 静态选项无需在每次更新时重读 } this.refreshOptions() }refreshOptions最终通过defaultOptions里的readAccessor(this.options)createQueryController.ts#L302重新执行 getter得到与当前宿主状态一致的新选项再通过observer.setOptions(options)应用到观测器上。onHostUpdate的触发源头是 Lit 的 ReactiveController 生命周期BaseController.hostUpdate() 在每次宿主更新时回调它而结果变化后setResult→queueUpdateBaseController.ts#L159-L171会用queueMicrotask触发host.requestUpdate()从而完成getter 读宿主状态 → 选项变化 → observer 更新 → 结果变化 → 宿主重渲染的响应式闭环。createMutationController、createInfiniteQueryController等采用完全相同的模式如 createMutationController.ts#L173-L179。这正是文档中那句 Lit Query APIs read function accessors during host updates 的具体含义getter 的求值不是任意的而是绑定在 Lit 的hostUpdate回调上天然与响应式状态同步且不会在非渲染时机重复求值。4. 在控制器 API 中的实际形态Accessor是 lit-query 对外 API 签名的通用包裹。types.ts 中导出的选项类型全部是Accessor 包裹的选项// QueryControllerOptions AccessorCreateQueryOptions... export type QueryControllerOptions... Accessor CreateQueryOptionsTQueryFnData, TError, TData, TQueryData, TQueryKey // InfiniteQueryControllerOptions、MutationControllerOptions 同理 export type MutationControllerOptions... Accessor CreateMutationOptionsTData, TError, TVariables, TOnMutateResult 因此所有create*Controller工厂函数的第二个参数都是Accessor...类型。index.ts#L5 已将Accessor与ValueAccessor一起从包入口导出供组件作者自行标注 props 或内部工具类型。一个依赖宿主状态的完整用法示意userId为响应式 state 属性getter 每次宿主更新时重读import { LitElement, html } from lit import { createQueryController } from tanstack/lit-query class UserTodosView extends LitElement { private userId 1 private readonly todos createQueryController(this, () ({ queryKey: [todos, this.userId], queryFn: () fetch(/api/users/${this.userId}/todos).then((r) r.json()), })) render() { const query this.todos() if (query.isPending) return htmlLoading... if (query.isError) return htmlError return htmlul${query.data.map((t) htmlli${t.title}/li)}/ul } }注意当userId变化、宿主重新渲染时onHostUpdate会用新选项重建 observer 的 options查询随之切换。若选项与宿主状态无关直接传静态对象如仓库示例 examples/lit/basic/src/main.ts#L54-L60 中的{ queryKey: [todos], queryFn: fetchTodosFromServer }即可构造期即完成初始化省去更新期的重读开销。5. 兄弟类型ValueAccessor与createValueAccessor读Accessor时应一并了解同文件定义的另一个类型ValueAccessorTaccessor.ts#L32-L43两者方向相反、配合使用export type ValueAccessorT (() T) { readonly current: T } export function createValueAccessorT(getter: () T): ValueAccessorT { const accessor (() getter()) as ValueAccessorT Object.defineProperty(accessor, current, { get: getter, enumerable: true, }) return accessor }输入方向AccessorT——API 接受值或 getter输出方向ValueAccessorT——控制器返回可调用 带current属性的对象createValueAccessor通过Object.defineProperty让current成为一个实时 getter。createQueryController的返回值QueryResultAccessor就是ValueAccessorQueryObserverResult { refetch, suspense, destroy }createQueryController.ts#L42-L51所以渲染代码中this.todos()与this.todos.current等价。源码注释中的示例accessor.ts#L26-L30const query this.todos() const sameQuery this.todos.current这样Accessor系列类型在 lit-query 中构成了一个完整的对称设计宿主状态经Accessor流入控制器控制器结果经ValueAccessor流出到渲染代码。6. 使用建议与小结结合源码行为使用Accessor时可以遵循几条经验与宿主状态无关的选项传静态对象。静态选项在构造期即完成 observer 初始化createQueryController.ts#L128-L132且跳过每次hostUpdate中的重读分支依赖 props/state 的选项传 getter。getter 会在宿主更新时被readAccessor求值闭包捕获的this.xxx总是最新值无需手动重建控制器getter 应保持零参且轻量。它可能随宿主更新频繁执行应避免在其中发起请求或产生副作用求值结果会直接交给defaultQueryOptions/defaultMutationOptions参与 observer 合并queries列表、filters过滤器同样支持Accessor例如useIsFetching(this, () ({ queryKey: [todos, this.userId] }))。AccessorT看起来只是一行联合类型但它是 Lit Query 将 Lit 响应式生命周期与 TanStack Query 观察者模型对接的关键抽象一行T | (() T)配合readAccessor与hostUpdate钩子让声明式配置与响应式配置在同一组 API 签名下无缝共存。【免费下载链接】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),仅供参考