查询 Queries
查询基础
查询是一种对于与唯一键值相关联的异步数据源的声明性依赖。 查询可以与任何基于 Promise 的方法(包括 GET 和 POST 方法)一起使用,以从服务器获取数据。 如果你的方法修改了服务器上的数据,建议你改用修改
要在你的组件或自定义 Hook 中订阅一个查询,至少需要以下的参数来调用useQuery
Hook:
- 该查询的一个唯一的键值
- 一个返回 Promise 的函数:
- 解析数据,或
- 抛出错误
import { useQuery } from "@tanstack/vue-query";
const result = useQuery({ queryKey: ["todos"], queryFn: fetchTodoList });
这个唯一键值将在内部用于重新获取数据、缓存和在整个程序中共享该查询信息。
useQuery
返回的查询结果将包含所有关于该查询的信息,你可以用这些信息来进行排版和或数据驱动的任何动作:
const result = useQuery(["todos"], fetchTodoList);
result
对象包含一些非常重要的状态,你需要注意这些状态才能提高工作效率。
在任何给定时刻,查询只能处于以下状态之一:
isLoading
或者status === 'loading'
- 查询暂时还没有数据isError
或者status === 'error'
- 查询遇到一个错误isSuccess
或者status === 'success'
- 查询成功,并且数据可用
除了这些主要状态之外,取决于具体查询的状态,还有更多信息可用:
error
- 如果查询处于isError
状态,则可以通过error
属性获取该错误data
- 如果查询处于success
状态,则可以通过data
属性获得数据
对于大多数查询,通常先检查isLoading
状态,然后检查isError
状态,最后假设数据可用并呈现成功状态就足够了:
<script setup>
import { useQuery } from "@tanstack/vue-query";
const { isLoading, isError, data, error } = useQuery({
queryKey: ["todos"],
queryFn: fetchTodoList,
});
</script>
<template>
<span v-if="isLoading">Loading...</span>
<span v-else-if="isError">Error: {{ error.message }}</span>
<!-- We can assume by this point that `isSuccess === true` -->
<ul v-else-if="data">
<li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
</ul>
</template>
如果你不喜欢布尔值,你也可以使用status
查询状态:
<script setup>
import { useQuery } from "@tanstack/vue-query";
const { status, data, error } = useQuery({
queryKey: ["todos"],
queryFn: fetchTodoList,
});
</script>
<template>
<span v-if="status === 'loading'">Loading...</span>
<span v-else-if="status === 'error'">Error: {{ error.message }}</span>
<!-- also status === 'success', but "else" logic works, too -->
<ul v-else-if="data">
<li v-for="todo in data" :key="todo.id">{{ todo.title }}</li>
</ul>
</template>
如果你在访问data
之前检查了loading
和error
,TypeScript 也会正确缩窄data
的类型。
FetchStatus
除了status
字段,result
对象,还会有一个额外的fetchStatus
属性,它有以下选项:
fetchStatus === 'fetching'
- 正在查询中fetchStatus === 'paused'
- 查询想要获取,但它被暂停了。在网络模式中阅读更多相关信息fetchStatus === 'idle'
- 该查询处于闲置状态
为什么有两种表示状态的东西(status
/fetchStatus
)?
后台刷新和数据过期重试(stale-while-revalidate)的逻辑使status
和fetchStatus
的所有组合成为了可能。比如说:
- 一个
state='success'
的查询通常处于fetchStatus='idle'
状态。但如果同时有后台重新获取动作,它也可能为fetchStatus='fetching'
状态。 - 一个没有数据的查询通常处于
status='loading'
状态和fetchStatus='loading
状态。如果同时无网络连接,它也可能为fetchStatus='paused'
状态。
所以请记住,一个查询可以处于fetchStatus='loading'
状态,但没有实际的在获取数据。
如何理清两者关系?这里有一个简单的经验法则:
status
告诉我们有关data
的状态:有或者没有?fetchStatus
告诉我们有关queryFn
的状态:在执行还是没在执行?