译零 TransZero · TanStack Query 中文文档
主站

响应式控制器 vs Hook

更新于 2026-11-02 Lit 查看英文原文 ↗

React Query 的示例使用 Hook。Lit Query 则使用响应式控制器。

二者职责相似:让组件订阅一个 QueryClient、读取最新结果,并在缓存变更时更新组件。但集成方式不同,因为 Lit 组件使用 ReactiveControllerHost 接口,而非 React 的渲染与 Hook 系统。

概念映射

React Query Lit Query
useQuery(options) createQueryController(this, options)
useQueries(options) createQueriesController(this, options)
useMutation(options) createMutationController(this, options)
useInfiniteQuery(options) createInfiniteQueryController(this, options)
useIsFetching(options) useIsFetching(this, options)
useIsMutating(options) useIsMutating(this, options)
useMutationState(options) useMutationState(this, options)
Hook 返回的对象 可调用的结果访问器
React 上下文提供器 QueryClientProvider 自定义元素
组件渲染重新执行 host.requestUpdate()

与宿主绑定的 API

Lit 中用于让组件订阅查询或修改状态的 API,其第一个参数接收一个 host:

TypeScript
1class TodosView extends LitElement {2  private readonly todos = createQueryController(this, {3    queryKey: ['todos'],4    queryFn: fetchTodos,5  })6}

this 是合法的,因为 LitElement 实现了 ReactiveControllerHost。该控制器会挂载到宿主上,在宿主连接时订阅,在查询结果变更时请求更新,并在宿主断开连接时取消订阅。

与宿主绑定的 API 包括:createQueryController、createQueriesController、createInfiniteQueryController、createMutationController、useIsFetching、useIsMutating 和 useMutationState。

useQueryClient 则不同:它不是响应式控制器,不接受宿主参数,不进行订阅,且若未配置唯一默认客户端,则同步抛出错误。仅在恰好有一个 QueryClientProvider 连接时,才应在命令式代码中使用它。在与宿主绑定的 API 内部,请优先使用提供器上下文,或显式传入一个 QueryClient。

读取结果

Lit Query 控制器创建器返回一个可调用的访问器,该访问器具有一个 current 属性:

TypeScript
1const query = this.todos()2const sameQuery = this.todos.current

渲染方法通常直接调用该访问器:

TypeScript
1render() {2  const query = this.todos()3 4  if (query.isPending) return html`Loading...`5  if (query.isError) return html`Error: ${query.error.message}`6 7  return html`<todo-list .items=${query.data}></todo-list>`8}

响应式选项

若查询选项依赖于宿主状态,请传入一个函数。Lit Query 会在宿主更新期间重新读取函数类型的访问器:

TypeScript
1class ProjectView extends LitElement {2  static properties = {3    projectId: { type: Number },4  }5 6  projectId = 17 8  private readonly project = createQueryController(this, () => ({9    queryKey: ['project', this.projectId],10    queryFn: () => fetchProject(this.projectId),11  }))12}

若选项是静态的,请传入一个对象。若你自行修改了静态选项对象,请调用控制器辅助方法(例如 refetch),使观察者感知到新选项;或者,对于响应式状态,更推荐使用函数访问器。

提供器上下文

与宿主绑定的 API 可接收显式的 QueryClient,但大多数应用会在 QueryClientProvider 下渲染。该提供器利用 Lit 上下文机制,将客户端传递给后代控制器。

TypeScript
1customElements.define('query-client-provider', QueryClientProvider)
TypeScript
1html`2  <query-client-provider .client=${queryClient}>3    <todos-view></todos-view>4  </query-client-provider>5`

自定义元素注册始终由应用自身负责。

QueryClientProvider 还会在进程级回退存储中注册其客户端,以供 useQueryClient 和 resolveQueryClient 使用。该回退机制有意设计为保守策略:

  • 若无提供器连接,useQueryClient() 将抛出错误。
  • 若恰好有一个独立客户端连接,useQueryClient() 返回该客户端。
  • 若在同一 JavaScript 上下文中连接了多个独立客户端,useQueryClient() 和 resolveQueryClient() 将抛出错误,因为此时回退行为存在歧义。

多根节点、微前端、模块共享的测试套件以及嵌套应用,均应避免依赖进程级回退机制。请确保将与宿主绑定的控制器渲染在正确的提供器之下,向控制器显式传入 QueryClient,或在测试间干净地断开提供器连接。

本页为 TanStack Query 文档(Lit 版)的非官方中文翻译,原文由上游团队维护,遵循 MIT 许可。 译文如有偏差,以英文原文为准。

译自上游 59d11de