框架
版本

Queries

Query 基础知识

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

要在你的组件或自定义 hooks 中订阅 query,请调用 useQuery hook,至少需要

  • query 的唯一键
  • 一个返回 promise 的函数,该 promise
    • 解析数据,或
    • 抛出错误
tsx
import { useQuery } from '@tanstack/react-query'

function App() {
  const info = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })
}
import { useQuery } from '@tanstack/react-query'

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

你提供的唯一键在内部用于重新获取、缓存和在整个应用程序中共享你的 queries。

useQuery 返回的 query 结果包含关于 query 的所有信息,你将在模板和数据的任何其他用法中需要这些信息

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

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

  • isPendingstatus === 'pending' - query 还没有数据
  • isErrorstatus === 'error' - query 遇到错误
  • isSuccessstatus === 'success' - query 成功,数据可用

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

  • error - 如果 query 处于 isError 状态,则可以通过 error 属性访问错误。
  • data - 如果 query 处于 isSuccess 状态,则可以通过 data 属性访问数据。
  • isFetching - 在任何状态下,如果 query 正在获取数据(包括后台重新获取),则 isFetching 将为 true

对于大多数 queries,通常只需检查 isPending 状态,然后检查 isError 状态,最后,假设数据可用并渲染成功状态

tsx
function Todos() {
  const { isPending, isError, data, error } = useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
  })

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

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

  // We can assume by this point that `isSuccess === true`
  return (
    <ul>
      {data.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}
function Todos() {
  const { isPending, isError, data, error } = useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
  })

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

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

  // We can assume by this point that `isSuccess === true`
  return (
    <ul>
      {data.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

如果布尔值不是你喜欢的,你也可以使用 status 状态

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

  if (status === 'pending') {
    return <span>Loading...</span>
  }

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

  // also status === 'success', but "else" logic works, too
  return (
    <ul>
      {data.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}
function Todos() {
  const { status, data, error } = useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
  })

  if (status === 'pending') {
    return <span>Loading...</span>
  }

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

  // also status === 'success', but "else" logic works, too
  return (
    <ul>
      {data.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

如果你已经检查了 pendingerror,TypeScript 也会正确缩小 data 的类型。

FetchStatus

除了 status 字段之外,你还将获得一个额外的 fetchStatus 属性,其中包含以下选项

  • fetchStatus === 'fetching' - query 当前正在获取数据。
  • fetchStatus === 'paused' - query 想要获取数据,但它已暂停。在 网络模式 指南中阅读更多关于此内容的信息。
  • fetchStatus === 'idle' - query 当前未执行任何操作。

为什么有两种不同的状态?

后台重新获取和 stale-while-revalidate 逻辑使 statusfetchStatus 的所有组合都成为可能。例如

  • 处于 success 状态的 query 通常处于 idle fetchStatus,但如果正在进行后台重新获取,它也可能处于 fetching
  • 挂载且没有数据的 query 通常处于 pending 状态和 fetching fetchStatus,但如果没有网络连接,它也可能处于 paused 状态。

因此请记住,query 可能处于 pending 状态,但实际上并未获取数据。作为经验法则

  • status 提供关于 data 的信息:我们是否有任何数据?
  • fetchStatus 提供关于 queryFn 的信息:它是否正在运行?

进一步阅读

有关执行状态检查的另一种方法,请查看 社区资源