使用 react-query 进行更清晰的数据获取
我认为数据获取在 React 世界中不如状态管理那么重要和引人注目。人们经常将客户端状态和服务器状态组合到他们的状态管理解决方案中。我所说的服务器状态是指来自后端服务器的数据。例如,在 Redux 设置中,客户端状态和来自服务器的数据存储在存储中,更新通过 Action 和 Reducer 处理。客户端状态的变化通常会导致服务器状态的变化,因此在大多数情况下将它们组合起来是合理的。但我认为它们是两个独立的实体,如果处理得当,在某些情况下我们甚至可以摆脱客户端状态管理解决方案。
我开始寻找分离客户端和服务器状态管理的解决方案。我从 Angular 的背景转入 React 世界,想要一些简单的方案,比如将服务器数据存储在服务中,然后将其注入到组件中,这样就万事大吉了。在 React 中,如果多个组件都需要你获取的数据,你就必须维护一个全局状态管理方案。
react-query 来帮忙
然后,我研究了执行数据获取和维护服务器状态的库。我偶然发现了React-Query,然后就一鸣惊人!它满足了我的所有需求,甚至更多。它提供了一种维护服务器状态全局上下文的方法,并且以极低的配置提供了一个出色的缓存解决方案。此外,swr也同样出色。
例子
好了,闲话少叙。我们开始写代码吧。我通常这样设置我的 React 项目。我有一个文件夹叫做 ,pages
里面存放了所有顶级路由。components
一个文件夹存放了所有 UI 组件。还有一个文件夹叫做api
,里面存放了所有服务器端 API。
假设我们有一个产品实体。该产品实体包含所有 CRUD 操作。因此,产品实体中需要包含以下 API 调用
1. Fetch all products
2. Fetch a specific product
3. Add a new product
4. Edit a product
5. Delete a product
react-query
为我们提供了一个useQuery
可用于所有查询的钩子。这应该涵盖了上面列表中的第 1 点和第 2 点。
我们将通过包装 来为产品创建自己的数据获取钩子useQuery
。
让我们回顾一下如何使用来设置数据获取函数react-query
。
获取产品
我们先从获取产品开始。基本的实现useQuery
看起来 没什么特别的。我们传入一个唯一的 ID作为第一个参数,并传入一个 fetch 函数来实际进行 API 调用。key
useQuery
它为我们提供了加载和错误状态,我认为这很棒
我们已经完成了数据获取的设置,但功能远不止于此。任何列表页面都会有其他功能,例如search
、等等filters
。pagination
而 React-Query 让添加这些功能变得非常简单。让我们开始设置吧。
分页
在我们的Products
组件中,我们可以将page
和limit
值作为状态。page
表示当前页码,limit
表示页面上要显示的产品数量。
下一步是将它与我们的useFetchProducts
钩子连接起来。让我们useFetchProducts
将page
和limit
作为参数。
让我们来分析一下这里发生了什么。这个useFetchProducts
钩子现在接受page
和limit
作为参数。它还将这两个参数添加到key
,并将它们添加到获取 URL 中。
太棒了!就是这样。我们现在实现了分页功能。现在,每当组件中的page
和 的值发生变化时,react-query 都会自动触发 API 请求并更新 UI。limit
Products
搜索
另一个重要的通用功能是搜索。因此,让我们name
在产品字段中添加一个搜索功能。你可能已经猜到了,这与分页过程完全相同。我们将name
在状态中添加一个字段,并将此状态值传递给我们的useFetchProducts
钩子。
我们的useFetchProducts
意愿看起来是这样的。
类似地,我们可以将任意数量的过滤/搜索参数挂载到我们的useFetchProducts
钩子上。此钩子可以跨多个组件使用,无需任何全局状态管理系统。
缓存
缓存无疑是我最喜欢的 React-Query 功能。只需极少的代码,我们就能搭建一个强大的缓存系统。以我们的产品示例为例,假设我们希望产品缓存 10 秒。我们可以通过添加选项来实现staleTime
。 这样,每当使用相同的、和调用此钩子时,都会使用缓存中的数据。page
limit
name
这里需要重点理解的是
key
选项。它key
唯一地标识一个请求。因此,值为 1 的请求page
与值为 2 的请求是不一样的。page
只有当三个键值都相同时,才会使用缓存中的值。
更新内部缓存
react-query
还允许我们访问其内部缓存。我们可以随时更新此缓存。这意味着,我们可以设置单个产品的内部缓存值。
想象一下,我们获取了产品列表并将其显示在屏幕上。用户点击某个产品,我们会将其带到产品页面。在产品页面中,我们必须获取产品的详细信息并显示出来。但是!产品的详细信息已经在 React-query 的内部缓存中了。如果我们可以使用缓存而不是 API 调用呢?
让我们从创建一个useFetchProduct
用于获取单个产品的钩子开始。
这里没什么特别的。和我们之前做的差不多,只是它接收id
一个参数。
这里要注意的是['product', id]
它的键。我们将一个产品的键关联到id
它的键上。
现在到了有趣的部分,每当我们获取产品列表时,我们都会使用每个单独产品的值设置内部缓存。react-query
公开一个useQueryClient
为我们提供内部缓存的钩子。
每当我们的产品列表成功获取时,onSuccess
就会调用 API 响应的函数。我们循环遍历每个产品,并使用该setQueryData
方法将其存储在缓存中。
现在,每当用户从产品列表页面移动到单个产品页面时,都会使用缓存中的值,而不是进行 API 调用。
结论
所以,我发现 React-Query 是一款极其简单且强大的数据获取解决方案。使用 React-Query 后,我甚至从一些项目中移除了全局状态管理解决方案。快去他们的代码库里表达一下我的喜爱吧!
干杯!
文章来源:https://dev.to/siddharthvenkatesh/cleaner-data-fetching-with-react-query-4klg