很早之前就看到 React Query 在前端掘金圈子里火了一把,一直想学却因为种种原因没有开始。这一阵子闲下来了一些,快速学习了一下并且在自己的小项目里上手用了一番,体验非常不错。所以在这里以 React Query 为例写一篇 TanStack Query 小小的快速上手指南。
React Query
TanStack Query (FKA React Query) is often described as the missing data-fetching library for web applications, but in more technical terms, it makes fetching, caching, synchronizing and updating server state in your web applications a breeze.
TanStack Query(前称 React Query,在下文中我们也采用这个称呼)通常被形容为 Web 应用所缺失的数据请求库。更专业的说法是,他让你的 web 应用中的请求、缓存、同步与更新服务端状态更加轻而易举了。
从我这段时间的使用体验来看,其中对于请求与缓存的处理可以说是 React Query 给我带来的最显著的提升。
以这样一段请求为例👇🏻
1function getListData() {
2 return axios.get('https://xxxx');
3}
4
5function List() {
6
7 const [data, setData] = useState([])
8
9 const [loading, setLoading] = useState(false)
10
11
12 const queryData = () => {
13 setLoading(true)
14 getListData().then((res) => {
15
16 setData(res.data.data)
17 }).catch((error) => {
18
19 }).finally(() => {
20 setLoading(false)
21 })
22 }
23
24 useEffect(() => {
25
26 if (fulfilled) {
27 queryData();
28 }
29 }, [])
30
31
32
33}
使用 React Query 管理请求后,我们可以这样写(用过 ahooks 的 useRequest 的小伙伴应该很熟悉这种写法)
1function List() {
2
3 const { data, isFetching } = useQuery({
4 queryFn: getListData,
5 queryKey: ["list", "query"],
6 enabled: fulfilled,
7 });
8
9
10
11}
在外层,我们需要创建一个 QueryClient
并使用 QueryClientProvider
来提供一个查询的上下文。
1const queryClient = new QueryClient()
2
3function App() {
4 return (
5 <QueryClientProvider client={queryClient}>
6 <Todos />
7 </QueryClientProvider>
8 )
9}
我们把冗长的请求逻辑全部都交由 React Query 来帮我们处理,我们只需要关心请求的状态和数据即可。
更详细一些
让我们聚焦在例子中 useQuery 这个方法上
1const { data, isFetching } = useQuery({
2 queryFn: getListData,
3 queryKey: ["list", "query"],
4 enabled: fulfilled,
5});
入参
对于入参,这里我们就需要介绍一下 React Query 中最关键的两个参数:queryFn
和 queryKey
。
查询函数(queryFn)需要是能够返回 Promise 的任意函数。而该 Promise 的返回值将会被填充至 useQuery 返回的 结果数据 data
或是 错误 error
。
查询键(queryKey)需要是一个数组,其元素可以是任何可以被序列化的类型。
当然, React作为一个开箱即用的库,其本身还包含着一些默认配置。如果你发现 Devtool 的网络 tab 中时不时冒出来一个预期意外的请求。不要着急提Bug,这可能是以下几个默认开启的配置项在“搞鬼”。
refetchOnMount
:在组件挂载时自动请求refetchOnWindowFocus
:在页面被重新focus时自动请求refetchOnReconnect
:网络重新连接时自动请求
除此之外,还有一种配置会导致重复的请求行为。不过这个需要手动开启,一般不会在开发者不知情的情况下触发请求。
refetchInterval
:定时请求
对于那些默认的配置,你可以通过在 useQuery
的入参中关闭他们,或者在创建 queryClient
的时候就将他们全局关闭。
1const queryClient = new QueryClient({
2 defaultOptions: {
3 queries: {
4 refetchOnReconnect: false,
5 refetchOnWindowFocus: false,
6
7 },
8 },
9});
返回
对于 useQuery
返回的结果,一翻文档发现有25个属性
1const {
2 data,
3 dataUpdatedAt,
4 error,
5 errorUpdateCount,
6 errorUpdatedAt,
7 failureCount,
8 failureReason,
9 fetchStatus,
10 isError,
11 isFetched,
12 isFetchedAfterMount,
13 isFetching,
14 isInitialLoading,
15 isLoading,
16 isLoadingError,
17 isPaused,
18 isPlaceholderData,
19 isPreviousData,
20 isRefetchError,
21 isRefetching,
22 isStale,
23 isSuccess,
24 refetch,
25 remove,
26 status
27} = useQuery(options);
大多数变量都可以见名知意,但是有一些细心的小伙伴可能发现了,这里的状态有非常多种,看起来貌似非常复杂。别急,让我们细细梳理一番。
在 React Query 中,我们有两个独立的状态 fetchStatus
和 status
,分别对应请求本身的状态和结果的状态。什么意思嘞?
请求本身的状态 fetchStatus
,也就是指我们的请求函数 queryFn
的状态,它在执行还是在摸鱼?useQuery
给了我们以下几种状态。当 fetchStatus
为 xx 时,
fetching
:该请求函数正在卖力干活!对应isFetching
。pause
:请求函数本应干活,但是因为网络等原因被迫暂停了。对应isPause
。idle
:该请求函数正在卖力摸鱼(空闲)!对应isIdle
。
而 status
则是对结果 data
的状态描述,我的数据是一个什么样的状态?当 status
为 xx 时,
loading
:你先别急,还没数据。对应isLoading
。error
:你的数据遇到了点错误,具体信息可以看看返回值中的error
。对应isError
。success
:你的数据安全获取到了,存在data
里啦。对应isSuccess
。
这些状态一般来说就足以支撑我们绝大多数的场景了。
关于查询键
其实了解了上面的内容,已经可以开始上手开发了。不过对于查询键,咱还是想要多说两句。React Query 作为一个请求管理库,核心就是要将不同的请求统一管理。而对于不同的请求,React Query 通过唯一的 queryKey
来进行标识和分组。
举个🌰,对于这些个 query
1const queryA = useQuery(["a1", "b1", "c1"], queryFnA);
2const queryB = useQuery(["a1", "b1", "c2"], queryFnB);
3const queryC = useQuery(["a1", "b2", "c1"], queryFnC);
4const queryD = useQuery(["a2", "b1", "c1"], queryFnD);
你可以想象成 React Query 维护了这样的一个集合
在未来,我们需要用 React Query 的更高级的功能时,特别是对一些特定的 query 进行操作时,我们只需要通过 queryKey
就可以轻松查找到我们想要的 query 了。
例如我需要找出 queryA 和 queryB ,那么我就可以通过 ["a1", "b1"]
来筛选得到想要的结果。
所以,在设计或者编写 queryKey
的时候,建议“三思而后行”。
最后
到这里,这篇小小的指南也要走到尽头了,但 React Query 才刚刚开始,在本文中,我们只讨论了最基础的查询,如果你想实现更多场景,例如分页,无限滚动等。亦或是向服务端发送删除,更新一类的请求(useMutation)。还是需要在文档中继续学习一番。
这里还推荐一下修仙大橙子dalao的专栏,也可以配合文档食用~
在阅读 React Query 的文档时,我发现了这样一段话
Out of the box, TanStack Query is configured with aggressive but sane defaults. Sometimes these defaults can catch new users off guard or make learning/debugging difficult if they are unknown by the user.
TanStack 是开箱即用的,使用了一套侵入性但健全的出厂配置。如果不知道这些出厂配置的话,可能会使新用户猝不及防,或是让他们的学习和debug变得困难。
想到我很早之前想学习 React Query 的时候,也是受到了某些“坑”的影响,转身干别的事去了(不可取不可取)。我希望在读完这篇小小的指南后,可以帮助你们平缓地度过这一段陡坡~