携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
这是我关于 ahooks - useRequest 系列文章的第一篇,其他两篇请查看:
关于 ahooks
2022年的今天,在 React 中使用 Hook 已经是常规的不能再常规的操作了,我们会大量的通过组合 React 提供的 Hook,创建属于自己业务的专属自定义 Hook,亦或是各种工具 Hook。
阿里前端团队出品的 ahooks 正是这样一套 Hook 工具集,里面提供数十个常用的 Hook,可以极大的方便我们的日常开发。
今天我们要着重介绍的。就是 ahooks 项目中最为重量级的一个 hook ,useRequest。
为什么用 useRequest
为什么要用 useRequest,其实要从状态说起。在过去项目开发中我们经常将 用户 UI 交互状态 与 服务端状态 混为一谈,经常是 Redux 一把嗦,通过 fetch 获取到数据用,使用 useState 将数据作为状态,最终渲染到页面。
这样做看起来并没有什么问题,很多项目也都是这样写的。但是 用户 UI 交互状态 是实时性较强的,是我们作为前端可控的状态,而 服务端状态 则涉及到 http 请求,他是异步的、是不完全可控的。
例如一个网络请求其实不光只有最终的数据这一个状态,还有 loading、error等状态,可能还涉及到请求失败后的 retry,一些服务端状态变更不频繁、但是前端需要频繁调用的,还涉及到数据的状态缓存与共享。
仅仅是上面那我们说的这些就已经涉及了大量的状态管理,这样的状态管理显然是有别于 用户 UI 交互状态 的,因此 SWR、react-query、rtk-query这些专注于服务端状态管理的库应运而生.
如果你在之前接触过 SWR 或者是 react-query,那么你可能会比较好的理解 useRequest,你可以将它看作是一个轻量级的 react-query。
快速上手
我们写一个模拟请求用户信息的组件,我们用普通的方式写的话,大致是这样的:
1 | javascript复制代码// 模拟异步请求 |
就像我们之前说的,这种普通的请求方式缺少 loading
、error
等状态,我们只需要简单的修改代码就能通过 useRequest
实现。
1 | javascript复制代码function App() { |
如你所见,他真的非常简单,我们只需要传入一个 Promise ,剩下的全部交给 useRequest
就可以了!
useRequest
的第一个参数 service 是一个异步函数,在组件初次加载时,会自动触发该函数执行。同时自动管理该异步函数的 loading
, data
, error
等状态。
手动请求
useRequest 是自定触发请求的,也就说当组件挂载到 DOM 树上后,请求会立即发出。如果我们希望手动触发请求,可以为 useRequest 函数配置第二个参数。
第二参数是一个 options 配置,如果设置了 options.manual = true
,则 useRequest
不会默认执行,需要通过 run
来触发执行。
1 | arduino复制代码const { data, loading, error, run } = useRequest(fetchUserInfo, { |
刷新
不同于 run
函数可以接收参数,refresh
不接受参数,它会自动的使用上一次调用传入的参数来发起请求。
1 | arduino复制代码const { data, loading, error, run, refresh} = useRequest(fetchUserInfo, { |
取消请求 cancel
一般来说,我们不需要处理取消请求,useRequest
会自动在组件卸载时取消请求。
1 | go复制代码const { data, loading, error, cancel} = useRequest(fetchUserInfo); |
突变 mutate
突变这个概念在 SWR、react-query 中也是存在的,在 ahooks 中使用它非常简单,我们可以把它看成是一个 setData
函数,它可以修改由 useRequest 返回的 data 状态。
1 | kotlin复制代码const { data, mutate} = useRequest(fetchUserInfo); |
它往往被用于乐观更新这样的场景!我会在后续文章中介绍如何使用 ahooks 的 useRequest 实现乐观更新。
options 可配置项简介
除了上面我们提到的 options.manual = true
,用于配置手动执行请求之外,options还有很多可选的配置,接下来我们简单介绍几个常用的配置。
1. 传递参数给 service
上面我们介绍了,参数1 service 一般是一个 结果值为 Promise 的函数,如果我们需要传参给这个函数应该怎么做?
答案还是 options,我们可以配置options.defaultParams
字段,如果只有一个参数,直接赋值即可,多参数则赋值一个元组即可。
1 | javascript复制代码function App() { |
2. loading状态延时 loadingDelay
一般我们会通过{loading && <div>Loading...</div>}
这样的代码来展示一段加载中动画,但是有时候在网络良好的状况下这个 loading 状态的持续时间非常短暂,如果这个请求是比较频繁调用的,那么就会不断的闪烁 加载动画,这样的体验是很差的,我们可以通过 loadingDelay
配置当 loading时间超过这个值时才展示loading动画
1 | php复制代码const { data, loading, error, run } = useRequest(fetchUserInfo, { |
3. 生命周期
useRequest 提供了多个生命周期回调函数:
- onBefore?: (params: TParams) => void; //在请求之前
- onSuccess?: (data: TData, params: TParams) => void; //请求成功
- onError?: (e: Error, params: TParams) => void; //请求失败
- onFinally?: (params: TParams, data?: TData, e?: Error) => void; //请求结束
1 | javascript复制代码 const { data, loading, error, run, refresh } = useRequest(fetchUserInfo, { |
4. 轮询
我们只需要简单配置一个属性,就可以将请求设置为轮询模式。
1 | go复制代码const { data, loading, error} = useRequest(fetchUserInfo, { |
我们还可以通过配置 pollingErrorRetryCount
字段,设置轮询错误重试次数。如果设置为 -1,则无限次,当轮询过程出错到达计数时,停止轮询。
配置 pollingWhenHidden
可以设置在页面隐藏时,是否继续轮询。如果设置为 false,在页面隐藏时会暂时停止轮询,页面重新显示时继续上次轮询。
如果设置 options.manual = true
,则初始化不会启动轮询,需要通过 run/runAsync
触发开始。
5. ready
ready 的效果其实有点等同于 run 函数,每当 ready 变成 true 时,就会发起一次请求,调用参数1传入的 Promise 异步函数。需要注意的是有参数的情况,ready是用默认参数发起请求,即使后续多次 改变 ready 的状态,他也是使用我们设置的 options.defaultParams
来传递给 service 的。这一定一定要注意,他的调用效果相当于是拿着默认参数的 refresh!
它相当于一个提供了一个总开关,只有当该条件满足时才允许发送请求,无论时自动请求还是手动请求,都受到该字段限制。
1 | javascript复制代码function App() { |
6. 依赖刷新
useRequest 提供了一个 options.refreshDeps
参数,当它的值变化后,会重新触发请求。它的效果基本等同于手写 useEffect。
例如:
1 | scss复制代码 const [id, setId] = useState(555); |
总结
行文至此,想必你应经对如何使用 useRequest
有了一定的了解,在后续文章中,我会继续介绍 useRequest
中的其他高级用法,例如 swr 缓存、请求的防抖、节流,还有上面我们说的 乐观更新 等等。
PS:再本文中,大写的 SW R特指的由 Next.js 团队推出的 SWR库,小写的 swr 则指的是 stale-while-revalidate
这一概念,请注意区分。
本文转载自: 掘金