比较 | React Query vs SWR vs Apollo vs RTK Query vs React Router
该比较表力求尽可能准确和公正。如果你在使用这些库中的任何一个,并且认为信息可以得到改善,请随时使用此链接来提交更改(带有注释或声明的证据)
特性/功能的等级:
- ✅ 一级(1st-class),内置,无需添加任何配置或代码即可使用
- 🟡 受支持,但作为非官方的第三方或社区组件/贡献
- 🔶 受支持和记录,但需要额外的用户代码才能实现
- 🛑 没有官方支持或文档。
React Query | SWR | Apollo Client | RTK-Query | React Router | |
---|---|---|---|---|---|
Github Repo / Stars | |||||
平台要求 | React | React | React, GraphQL | Redux | React |
他们的比较 | (none) | (none) | Comparison | (none) | |
支持的查询语法 | Promise, REST, GraphQL | Promise, REST, GraphQL | GraphQL. Any (Reactive Variables) | Promise, REST, GraphQL | Promise, REST, GraphQL |
支持的框架 | React | React | React + Others | Any | React |
缓存策略 | 分层的 Key -> Value | 唯一的 Key -> Value | 归一化的结构 | 唯一的 Key -> Value | 嵌套的路由 -> value |
缓存 key 的策略 | JSON | JSON | GraphQL Query | JSON | Route Path |
缓存变更检测方法 | 深度比较 (稳定的序列化) | 浅比较 | 深度比较 (不稳定的序列化) | 引用相等 (===) | 路由变更 |
数据变更检测方法 | 深度比较 + 结构化共享 | 深比较(即dequal ) | 深度比较 (不稳定的序列化) | 引用相等 (===) | 程序加载 |
数据缓存(memo) | 全量的结构化共享 | 一致性(===) | 归一化的一致性 | 一致性(===) | 一致性(===) |
打包后大小 | + | ||||
API 定义位置 | 组件中, 额外 config | 组件中 | GraphQL 语法 | 额外 config | 路由树的 config |
查询 | ✅ | ✅ | ✅ | ✅ | ✅ |
缓存 | ✅ | ✅ | ✅ | ✅ | 🛑 仅已激活的路由 8 |
开发者工具 | ✅ | 🟡 | ✅ | ✅ | 🛑 |
轮询/长轮询 | ✅ | ✅ | ✅ | ✅ | 🛑 |
并行查询 | ✅ | ✅ | ✅ | ✅ | ✅ |
有依赖的查询 | ✅ | ✅ | ✅ | ✅ | ✅ |
分页查询 | ✅ | ✅ | ✅ | ✅ | ✅ |
无限查询 | ✅ | ✅ | ✅ | 🛑 | 🛑 |
双向无限查询 | ✅ | 🔶 | 🔶 | 🛑 | 🛑 |
无限查询重新获取数据 | ✅ | ✅ | 🛑 | 🛑 | 🛑 |
滞后查询数据1 | ✅ | 🔶 | 🛑 | ✅ | ✅ |
选择器 | ✅ | 🛑 | ✅ | ✅ | N/A |
初始化数据 | ✅ | ✅ | ✅ | ✅ | ✅ |
滚动恢复 | ✅ | ✅ | ✅ | ✅ | ✅ |
缓存操作 | ✅ | ✅ | ✅ | ✅ | 🛑 |
过时数据的处理 | ✅ | ✅ | ✅ | ✅ | ✅ |
批量渲染及优化2 | ✅ | 🛑 | 🛑 | ✅ | ✅ |
自动垃圾收集 | ✅ | 🛑 | 🛑 | ✅ | N/A |
修改 Hook | ✅ | 🟡 | ✅ | ✅ | ✅ |
离线修改的支持 | ✅ | 🛑 | 🟡 | 🛑 | 🛑 |
预取 api | ✅ | 🔶 | ✅ | ✅ | ✅ |
查询取消 | ✅ | 🛑 | 🛑 | 🛑 | ✅ |
部分查询匹配3 | ✅ | 🛑 | 🛑 | ✅ | N/A |
超时重新验证 | ✅ | ✅ | ✅ | ✅ | 🛑 |
超时时间设置 | ✅ | 🛑7 | 🛑 | ✅ | 🛑 |
使用前查询/修改配置4 | ✅ | 🛑 | 🛑 | ✅ | ✅ |
窗口焦点重新获取数据 | ✅ | ✅ | 🛑 | 🔶 | 🛑 |
网络状态重新获取数据 | ✅ | ✅ | ✅ | 🔶 | 🛑 |
通用缓存的 Dehydration/Rehydration | ✅ | 🛑 | ✅ | ✅ | ✅ |
离线缓存 | ✅ (实验中) | 🛑 | ✅ | 🔶 | 🛑 |
React Suspense (实验中) | ✅ | ✅ | 🛑 | 🛑 | ✅ |
抽象的内核 | ✅ | 🛑 | ✅ | ✅ | 🛑 |
修改后自动重新获取数据5 | 🔶 | 🔶 | ✅ | ✅ | ✅ |
归一化缓存6 | 🛑 | 🛑 | ✅ | 🛑 | 🛑 |
Notes
1 滞后查询数据 - React Query 提供了一种在下一个查询加载时继续查看现有的数据的方法(类似于原生的 UX 更新方式). 在编写分页 ui 或无限加载 ui 时,这一点非常重要,因为在这些 ui 中,我们不希望在请求新查询时显示硬加载状态。其他库没有这种功能,它们会在新查询加载时为新查询呈现硬加载状态(除非已预取)。
2 渲染优化 - React Query 具有出色的渲染性能。默认情况下,它将自动跟踪哪些字段被访问过,并且仅在字段被更新时重新渲染组件。例如,因为它具有新数据,或表明它正在获取。React Query 还将更新批量化,以确保当多个组件使用同一个查询时,应用只重新呈现一次。如果你只对
data
或error
感兴趣,你可以通过设置notifyOnChangeProps
为['data', 'error']
来减少更多的渲染次数。此外,如果你觉得该优化过于激进,也可以设置notifyOnChangeProps:'all'
来使得组件在每次查询时都得以更新。
3 部分查询匹配 - 由于 React Query 使用确定性查询键(deterministic query key)来做序列化,因此,您无需知道要匹配的每个单独的查询键即可操作变量查询组。例如,您可以重新获取数据每个键中以
todos
开头的查询,而不管变量如何,也可以定位具有(或不具有)变量或嵌套属性的特定查询,甚至可以使用过滤器功能仅匹配通过特定条件的查询。
4 使用前查询/修改配置 - 这只是一个花哨的名称,用来配置查询和修改在被使用之前的行为方式。例如,查询可以事先用默认值完全配置,当需要使用它时,只需要
useQuery(key)
,而不是每次使用时都需要传递 fetcher 和可选项。SWR 确实具有此功能的部分形式,它允许您预配置默认的访存程序,但只能将其预配置为全局访存程序,而不是在每个查询的基础上,而且绝对不用于修改。
5 修改后自动重新获取数据 - 为了在修改发生后实现真正的自动重取,需要有一个 schema (如 graphQL 提供的) 以帮助组件知道如何识别该 schema 中的单个实体(entity)和实体类型(types)的启发式方法(heuristics)。
6 归一化缓存 - React Query 和 SWR 当前不支持自动归一化的缓存,该缓存描述了在平面架构中如何存储实体以避免某些高级数据的重复。
7 SWR 的不可变模式 - SWR 提供了一种"不可变"模式,允许您在缓存的生命周期里只获取一次查询。然而它任然没有关于过期时间或有条件的自动重新验证相关的概念。
8 React Router 的持久化缓存 - React Router 不缓存除当前匹配的路由之外的数据。如果一条从路由切换到另外的路由,则该路由的数据将丢失.