Skip to main content

查询 Queries

查询基础

查询是一种对于与唯一键值相关联的异步数据源的声明性依赖。 查询可以与任何基于 Promise 的方法(包括 GET 和 POST 方法)一起使用,以从服务器获取数据。 如果你的方法修改了服务器上的数据,建议你改用修改

要在你的组件或自定义 Hook 中订阅一个查询,至少需要以下的参数来调用useQueryHook:

  • 该查询的一个唯一的键值
  • 一个返回 Promise 的函数:
    • 解析数据,或
    • 抛出错误
import { useQuery } from "react-query";

function App() {
const info = useQuery({ queryKey: ["todos"], queryFn: fetchTodoList });
}

这个唯一键值将在内部用于重新获取数据、缓存和在整个程序中共享该查询信息。

useQuery返回的查询结果将包含所有关于该查询的信息,你可以用这些信息来进行排版和或数据驱动的任何动作:

const result = useQuery({ queryKey: ["todos"], queryFn: fetchTodoList });

result对象包含一些非常重要的状态,你需要注意这些状态才能提高工作效率。 在任何给定时刻,查询只能处于以下状态之一:

  • isLoading 或者 status === 'loading' - 查询暂时还没有数据
  • isError 或者 status === 'error' - 查询遇到一个错误
  • isSuccess 或者 status === 'success' - 查询成功,并且数据可用

除了这些主要状态之外,取决于具体查询的状态,还有更多信息可用:

  • error - 如果查询处于isError状态,则可以通过error属性获取该错误
  • data - 如果查询处于isSuccess状态,则可以通过data属性获得数据

对于大多数查询,通常先检查isLoading状态,然后检查isError状态,最后假设数据可用并呈现成功状态就足够了:

function Todos() {
const { isLoading, isError, data, error } = useQuery({
queryKey: ["todos"],
queryFn: fetchTodoList,
});

if (isLoading) {
return <span>Loading...</span>;
}

if (isError) {
return <span>Error: {error.message}</span>;
}

// 现在我们可以假设 `isSuccess === true`
return (
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}

如果你不喜欢布尔值,你也可以使用status查询状态:

function Todos() {
const { status, data, error } = useQuery({
queryKey: ["todos"],
queryFn: fetchTodoList,
});

if (status === "loading") {
return <span>Loading...</span>;
}

if (status === "error") {
return <span>Error: {error.message}</span>;
}

// 也是 `status ==='success'`,但是 “else” 逻辑也起作用
return (
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}

如果你在访问data之前检查了loadingerror,TypeScript 也会正确缩窄data的类型。

FetchStatus

除了status字段,result对象,还会有一个额外的fetchStatus属性,它有以下选项:

  • fetchStatus === 'fetching' - 正在查询中
  • fetchStatus === 'paused' - 查询想要获取,但它被暂停了。在网络模式中阅读更多相关信息
  • fetchStatus === 'idle' - 该查询处于闲置状态

为什么有两种表示状态的东西(status/fetchStatus)?

后台刷新和数据过期重试(stale-while-revalidate)的逻辑使statusfetchStatus的所有组合成为了可能。比如说:

  • 一个state='success'的查询通常处于fetchStatus='idle'状态。但如果同时有后台重新获取动作,它也可能为fetchStatus='fetching'状态。
  • 一个没有数据的查询通常处于status='loading'状态和fetchStatus='loading状态。如果同时无网络连接,它也可能为fetchStatus='paused'状态。

所以请记住,一个查询可以处于status='loading'状态,但没有实际的在获取数据。 如何理清两者关系?这里有一个简单的经验法则:

  • status告诉我们有关data的状态:有或者没有?
  • fetchStatus告诉我们有关queryFn的状态:在执行还是没在执行?

延伸阅读

如果你对于执行状态检查的另一种方法感兴趣的话,请参阅此社区资源