为什么需要在 React/React Native 项目中使用 React-Query
介绍
您是否遇到过管理服务器状态的问题?或者发现自己编写的代码冗长又滑稽,只是为了从服务器获取数据?如果您有以上任何一种情况,我真心觉得您需要了解一下 react-query。
服务器状态是实际存储在服务器上的状态,然后临时存储在客户端以便快速访问(如用户数据、交易数据)
React 缺乏标准的数据获取范式,这导致了多个状态管理库的诞生。然而,这些库并不完全支持正确处理异步数据(服务器状态)。异步数据通常在组件级别处理,其中通常会跟踪与其相关的每个状态,例如加载、错误、数据、刷新等。随着跟踪的服务器状态数量的增加,管理服务器状态的难度也会增加。
React Query 是一个能够有效管理和跟踪服务器状态的库。在本文中,我将重点介绍如何使用 React-Query,以及为什么应该在你的下一个应用程序中使用它。
React Query 通常被描述为 React 缺少的数据获取库,但从更专业的术语来说,它使得在 React 应用程序中获取、缓存、同步和更新服务器状态变得轻而易举。
先决条件
您需要掌握以下列出的技术的基本知识
- 反应
- React hooks(基础)
- 状态管理库(基础)
为什么要使用 React Query?
在简单的网络请求/调用中,最重要的三个服务器状态是加载、错误和数据服务器状态。使用状态管理库来存储这些状态效率不高,因为整个应用程序不需要知道这些状态,它们只与需要它们的组件相关。
典型的应用程序全局状态如下所示
const globalState = {
user: {},
appSettings: {
appVersion: "",
theme: "light", // yes I am a thug
},
transactions: {
data: [],
transactionLoading: true,
transactionError: null,
}
};
在将状态添加到全局状态管理库之前,我会问自己一个问题:“应用是否需要知道这些数据?” 通常情况下,几乎所有服务器状态都无法通过这个测试。我的应用不需要知道事务何时加载或出错,因为这些状态很可能只在一个组件中使用。由于这些服务器状态并非全局需要,因此下一个最佳决策是创建钩子来帮助管理基本的服务器状态。然而,这并不能消除处理多个服务器状态(例如缓存、刷新、重试等)的难度。React Query 提供了一种一致且直接的服务器状态管理方法,因为所有这些都已被抽象到库中。
说话不值一提,让我们行动起来吧!
安装
npm i react-query
# or
yarn add react-query
样本一
// https://codesandbox.io/s/reverent-sunset-rxwgl?file=/src/App.js
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const [loading, setLoading] = useState(true);
const [data, setData] = useState({});
const [error, setError] = useState(null);
useEffect(() => {
async function getRepos() {
try {
const repoData = await fetch(
"https://api.github.com/repos/tannerlinsley/react-query"
).then((res) => res.json());
setData(repoData);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
}
getRepos();
}, []);
if (loading) return "Loading...";
if (error) return "An error has occurred: " + error.message;
return (
<div className="App">
<h1>Traditional way of handling server State</h1>
<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>
</div>
);
}
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>
)
}
比较这些函数可以发现 useQuery hook 如何消除设置三种不同的状态、使用 useEffect、捕获错误并最终将加载设置为 false,处理所有这些可能非常麻烦,并且当管理多个状态(如无限列表或分页服务器状态)时,react-query 的精神开始显现,重新获取查询。
样本二
让我们看一下文档中的Rick and Morty示例,因为我认为这是一个更简洁的示例,可以突出显示 react-query 从您的应用程序中删除了多少复杂性。
// https://codesandbox.io/s/github/tannerlinsley/react-query/tree/master/examples/rick-morty?file=/src/Episodes.js:0-903
import React from "react";
import { Typography, Link } from "@material-ui/core";
import { Link as RouterLink } from "react-router-dom";
import { useQuery } from "react-query";
import fetch from "./fetch";
export default function Episodes() {
const { data, status } = useQuery("episodes", () =>
fetch("https://rickandmortyapi.com/api/episode")
);
if (status === "loading") {
return <p>Loading...</p>;
}
if (status === "error") {
return <p>Error :(</p>;
}
return (
<div>
<Typography variant="h2">Episodes</Typography>
{data.results.map(episode => (
<article key={episode.id}>
<Link component={RouterLink} to={`/episodes/${episode.id}`}>
<Typography variant="h6">
{episode.episode} - {episode.name} <em>{episode.airDate}</em>
</Typography>
</Link>
</article>
))}
</div>
);
}
获取剧集数据并根据状态有条件地进行渲染(这里不使用加载服务器状态,因为使用加载作为服务器状态存在一些缺陷,您可以在此处查看 Kent Dodds 的文章https://kentcdodds.com/blog/stop-using-isloading-booleans)。
const { data, status } = useQuery("episodes", () =>
fetch("https://rickandmortyapi.com/api/episode")
);
“episodes” 字符串称为查询键,用于跟踪和管理数据的缓存。查询键对于查询数据应该是唯一的。如果您离开页面然后返回,数据将立即从缓存中获取(请注意,数据在应用程序关闭时不会保留),并在后台重新获取。这是React-query 中的默认设置之一,值得一看,因为对于初学者来说,它可能会让您感到困惑。
本例中的大多数其他数据获取请求都将遵循此流程,我们尝试从服务器获取数据,如果它在缓存中,我们会获取数据,然后它在后台获取数据,如果不在,它会在前台获取数据,所有这些原始的服务器状态处理和它公开的方法使得 react-query 成为用于服务器状态的正确工具。
概括
因此,您需要在 React/React Native 项目中使用 react-query 的原因如下:
- 您无需编写冗长的代码来帮助管理服务器状态,react-query 直观地帮助您编写更干净、更简短的代码,因为所有这些管理都被抽象到 react-query 中。
- 该应用程序几乎总是使用最新的服务器状态进行更新。
- 您不必处理 useEffects。
致谢
React 查询文档
https://kentcdodds.com/blog/stop-using-isloading-booleans
https://kentcdodds.com/blog/application-state-management-with-react#server-cache-vs-ui-state
Pexels 上的 Anni Roenkae 拍摄的照片
文章来源:https://dev.to/benjamindaniel/why-you-need-to-use-react-query-in-your-react-react-native-project-2oog