React Query

React Query

React Query 为我们提供了诸如 useQuery 之类的自定义钩子来获取数据。在后台,这些挂钩管理许多事情,例如在初始获取后缓存数据,在后台重新获取数据等。React Query 经常被描述为 React 缺失的数据获取库,但在更多的技术术语中,它使你的 React 应用程序中获取、缓存、同步和更新服务器状态变得轻而易举。

Motivation

开箱即用的 React 应用程序并没有提供从组件中获取或更新数据的意见,所以开发者最终要建立自己的获取数据的方式。这通常意味着使用 React 钩子把基于组件的状态和效果拼凑在一起,或者使用更通用的状态管理库来存储和提供整个应用程序的异步数据。虽然大多数传统的状态管理库在处理客户端状态方面很出色,但它们在处理异步或服务器状态方面却不那么出色。这是因为服务器状态是完全不同的。首先,服务器状态:

  • 在一个你不控制或不拥有的地方被远程持久化
  • 需要异步的 API 来获取和更新
  • 意味着共享所有权,可以在你不知情的情况下被其他人改变
  • 如果你不小心,有可能在你的应用程序中变得过时。

一旦你掌握了应用程序中服务器状态的性质,甚至更多的挑战会随着你的发展而出现,比如说。

  • 缓存… (可能是编程中最难做到的事情)
  • 将对同一数据的多个请求简化为一个请求
  • 在后台更新过时的数据
  • 知道数据何时过期
  • 尽可能快地反映数据的更新
  • 性能优化,如分页和懒惰加载数据
  • 管理内存和服务器状态的垃圾收集
  • 用结构共享来记忆查询结果

如果你没有被这个清单压倒,那么这一定意味着你可能已经解决了所有的服务器状态问题,并应该获得奖励。然而,如果你像绝大多数人一样,你要么还没有解决所有这些挑战,要么还没有解决大部分挑战,而我们只是在抓紧时间。React Query 是管理服务器状态的最佳库之一。它开箱即用,零配置,效果惊人,而且可以随着你的应用程序的增长,按照你的喜好进行定制。React 查询允许你击败并克服服务器状态的棘手挑战和障碍,在你的应用程序数据开始控制你之前控制它。在更多的技术方面,React Query 将可能。

  • 帮助你从你的应用程序中删除许多复杂的和被误解的代码,只用少数几行 React Query 逻辑来代替。
  • 使你的应用程序更易维护,更容易建立新的功能,而不必担心新的服务器状态数据源的接线问题
  • 通过使你的应用程序感觉比以前更快、更灵敏,对你的终端用户产生直接影响。
  • 潜在地帮助你节省带宽和提高内存性能

对比

Comparsion React Query SWR (Website) Apollo Client (Website) RTK-Query (Website)
Github Repo / Stars
Platform Requirements React React React, GraphQL Redux
Their Comparison (none) (none) Comparison
Supported Query Syntax Promise, REST, GraphQL Promise, REST, GraphQL GraphQL Promise, REST, GraphQL
Supported Frameworks React React React + Others Any
Supported Query Keys JSON JSON GraphQL Query JSON
Query Key Change Detection Deep Compare (Stable Serialization) Referential Equality (===) Deep Compare (Unstable Serialization) Referential Equality (===)
Query Data Memoization Level Query + Structural Sharing Query Query + Entity + Structural Sharing Query
Bundle Size
img
img
img
img
API Definition On-Use, Declarative On-Use GraphQL Schema Declarative
Queries
Caching
Devtools 🟡
Polling/Intervals
Parallel Queries
Dependent Queries
Paginated Queries
Infinite Queries 🛑
Bi-directional Infinite Queries 🔶 🔶 🛑
Infinite Query Refetching 🛑 🛑
Lagged Query Data1 🛑 🛑
Selectors 🛑
Initial Data
Scroll Recovery
Cache Manipulation
Outdated Query Dismissal
Render Optimization2 🛑 🛑
Auto Garbage Collection 🛑 🛑
Mutation Hooks 🟡
Offline Mutation Support 🛑 🟡 🛑
Prefetching APIs 🔶
Query Cancellation 🛑 🛑 🛑
Partial Query Matching3 🛑 🛑
Stale While Revalidate
Stale Time Configuration 🛑 🛑
Pre-usage Query/Mutation Configuration4 🛑 🛑
Window Focus Refetching 🛑 🔶
Network Status Refetching 🔶
General Cache Dehydration/Rehydration 🛑
Offline Caching ✅ (Experimental) 🛑 🔶
React Suspense (Experimental) 🛑 🛑
Abstracted/Agnostic Core 🛑
Automatic Refetch after Mutation5 🔶 🔶
Normalized Caching6 🛑 🛑 🛑

Hello World

import { QueryClient, QueryClientProvider, useQuery } from "react-query";

const queryClient = new QueryClient();

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Example />
    </QueryClientProvider>
  );
}

function Example() {
  const { isLoading, error, data } = useQuery("repoData", () =>
    fetch("https://api.github.com/repos/tannerlinsley/react-query").then(
      (res) => res.json()
    )
  );

  if (isLoading) return "Loading...";

  if (error) return "An error has occurred: " + error.message;

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.description}</p>
      <strong>👀 {data.subscribers_count}</strong>{" "}
      <strong> {data.stargazers_count}</strong>{" "}
      <strong>🍴 {data.forks_count}</strong>
    </div>
  );
}

如果希望在类组件中使用,可以采取如下方式:

function UseQuery(props) {
  return props.children(useQuery(props.key, props.fn, props.options))
}

<UseQuery
  key=todos
  fn={() => getTodos()}
  options={{ staleTime: 5000 }}
>
  {query => {. . .}}
</UseQuery>