查询
初次接触 Lit Query?请先阅读 安装 和 快速上手,再将查询控制器集成到你的元素中。
查询基础
查询是对一个异步数据源的声明式依赖,该依赖与一个唯一查询键相关联。使用查询来读取服务端状态(server state)。如果某个函数用于创建、更新或删除服务端数据,请改用 修改。
在 Lit 中,使用 createQueryController 订阅查询:
TypeScript
1import { LitElement, html } from 'lit'2import { createQueryController } from '@tanstack/lit-query'3 4class TodosView extends LitElement {5 private readonly todos = createQueryController(this, {6 queryKey: ['todos'],7 queryFn: fetchTodos,8 })9 10 render() {11 const query = this.todos()12 13 if (query.isPending) return html`Loading...`14 if (query.isError) return html`Error: ${query.error.message}`15 16 return html`17 <ul>18 ${query.data.map((todo) => html`<li>${todo.title}</li>`)}19 </ul>20 `21 }22}该控制器需要:
- 一个
ReactiveControllerHost,通常为this,位于LitElement内部 - 一个唯一的
queryKey - 一个
queryFn,它返回 Promise,并在出错时抛出异常
返回的访问器暴露当前 QueryObserverResult。你可在 render 中调用它,或直接读取 .current:
TypeScript
1const query = this.todos()2const sameQuery = this.todos.current查询状态
查询在任一时刻仅处于一种主要状态:
isPending或status === 'pending':尚无可用数据isError或status === 'error':查询失败,且error可用isSuccess或status === 'success':数据可用
结果还包含 isFetching,它在初始加载或后台重新拉取期间可能为 true。
TypeScript
1render() {2 const query = this.todos()3 4 if (query.status === 'pending') {5 return html`<span>Loading...</span>`6 }7 8 if (query.status === 'error') {9 return html`<span>Error: ${query.error.message}</span>`10 }11 12 return html`<todo-list .items=${query.data}></todo-list>`13}TypeScript 会在你检查 pending 和 error 后对 query.data 进行类型收窄,然后再读取它。
拉取状态
status 字段描述数据是否可用。fetchStatus 字段描述查询函数当前正在执行的操作:
fetchStatus === 'fetching':查询正在进行拉取。fetchStatus === 'paused':查询本应拉取,但拉取已被暂停。fetchStatus === 'idle':查询未进行拉取。
这些状态被有意设计为相互独立。后台重新拉取和“过期时验证”(stale-while-revalidate)行为可能导致如下组合:
- 一个成功的查询若拥有缓存数据,在后台重新拉取运行期间,可能同时具有
status === 'success'和fetchStatus === 'fetching'。 - 一个尚无数据的查询,若拉取尚不能启动,则可能同时具有
status === 'pending'和fetchStatus === 'paused'。
在决定是否渲染数据时,请使用 status;在决定是否显示网络活动指示器时,请使用 fetchStatus 或 isFetching:
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`8 ${query.fetchStatus === 'fetching'9 ? html`<span>Refreshing...</span>`10 : null}11 <todo-list .items=${query.data}></todo-list>12 `13}响应式查询选项
当查询键或查询函数依赖于宿主(host)状态时,请使用选项 getter:
TypeScript
1class UserTodos extends LitElement {2 static properties = {3 userId: { type: String },4 }5 6 userId = ''7 8 private readonly todos = createQueryController(this, () => ({9 queryKey: ['todos', this.userId],10 queryFn: () => fetchTodos(this.userId),11 enabled: this.userId.length > 0,12 }))13}查询键用于缓存、重新拉取以及控制器间的数据共享。
重新拉取
访问器包含 refetch:
TypeScript
1html`<button @click=${() => this.todos.refetch()}>Refetch</button>`如需同时运行多个查询,请参阅 并行查询。