很早之前就看到 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 给我带来的最显著的提升。
以这样一段请求为例👇🏻
function getListData() {
return axios.get('https://xxxx');
}
function List() {
// 数据
const [data, setData] = useState([])
// 加载状态
const [loading, setLoading] = useState(false)
// ...
const queryData = () => {
setLoading(true)
getListData().then((res) => {
// ...
setData(res.data.data)
}).catch((error) => {
// ...
}).finally(() => {
setLoading(false)
})
}
useEffect(() => {
// 满足某种条件才请求
if (fulfilled) {
queryData();
}
}, [])
// ...
// return template;
}
使用 React Query 管理请求后,我们可以这样写(用过 ahooks 的 useRequest 的小伙伴应该很熟悉这种写法)
function List() {
// ...
const { data, isFetching } = useQuery({
queryFn: getListData, // 查询函数
queryKey: ["list", "query"], // 查询键
enabled: fulfilled, // 是否启用
});
// ...
// return template;
}
在外层,我们需要创建一个 QueryClient
并使用 QueryClientProvider
来提供一个查询的上下文。
const queryClient = new QueryClient()
function App() {
return (
<QueryClientProvider client={queryClient}>
<Todos />
</QueryClientProvider>
)
}
我们把冗长的请求逻辑全部都交由 React Query 来帮我们处理,我们只需要关心请求的状态和数据即可。
更详细一些
让我们聚焦在例子中 useQuery 这个方法上
const { data, isFetching } = useQuery({
queryFn: getListData, // 查询函数
queryKey: ["list", "query"], // 查询键
enabled: fulfilled, // 是否启用
});
入参
对于入参,这里我们就需要介绍一下 React Query 中最关键的两个参数:queryFn
和 queryKey
。
查询函数(queryFn)需要是能够返回 Promise 的任意函数。而该 Promise 的返回值将会被填充至 useQuery 返回的 结果数据 data
或是 错误 error
。
查询键(queryKey)需要是一个数组,其元素可以是任何可以被序列化的类型。
当然, React作为一个开箱即用的库,其本身还包含着一些默认配置。如果你发现 Devtool 的网络 tab 中时不时冒出来一个预期意外的请求。不要着急提Bug,这可能是以下几个默认开启的配置项在“搞鬼”。
refetchOnMount
:在组件挂载时自动请求refetchOnWindowFocus
:在页面被重新focus时自动请求refetchOnReconnect
:网络重新连接时自动请求
除此之外,还有一种配置会导致重复的请求行为。不过这个需要手动开启,一般不会在开发者不知情的情况下触发请求。
refetchInterval
:定时请求
对于那些默认的配置,你可以通过在 useQuery
的入参中关闭他们,或者在创建 queryClient
的时候就将他们全局关闭。
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnReconnect: false,
refetchOnWindowFocus: false,
// ...
},
},
});
返回
对于 useQuery
返回的结果,一翻文档发现有25个属性
const {
data,
dataUpdatedAt,
error,
errorUpdateCount,
errorUpdatedAt,
failureCount,
failureReason,
fetchStatus,
isError,
isFetched,
isFetchedAfterMount,
isFetching,
isInitialLoading,
isLoading,
isLoadingError,
isPaused,
isPlaceholderData,
isPreviousData,
isRefetchError,
isRefetching,
isStale,
isSuccess,
refetch,
remove,
status
} = 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
const queryA = useQuery(["a1", "b1", "c1"], queryFnA);
const queryB = useQuery(["a1", "b1", "c2"], queryFnB);
const queryC = useQuery(["a1", "b2", "c1"], queryFnC);
const queryD = useQuery(["a2", "b1", "c1"], queryFnD);
你可以想象成 React Query 维护了这样的一个集合
在未来,我们需要用 React Query 的更高级的功能时,特别是对一些特定的 query 进行操作时,我们只需要通过 queryKey
就可以轻松查找到我们想要的 query 了。
例如我需要找出 queryA 和 queryB ,那么我就可以通过 ["a1", "b1"]
来筛选得到想要的结果。
所以,在设计或者编写 queryKey
的时候,建议“三思而后行”。
最后
到这里,这篇小小的指南也要走到尽头了,但 React Query 才刚刚开始,在本文中,我们只讨论了最基础的查询,如果你想实现更多场景,例如分页,无限滚动等。亦或是向服务端发送删除,更新一类的请求(useMutation)。还是需要在文档中继续学习一番。
在阅读 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 的时候,也是受到了某些“坑”的影响,转身干别的事去了(不可取不可取)。我希望在读完这篇小小的指南后,可以帮助你们平缓地度过这一段陡坡~
感谢分享,谢谢
学到了,感谢
巨佬!收下我的膝盖