SWR与React Hooks最佳实践
在最近的一个需求中,第一次使用上swr这个库。效果很棒,解决了不少痛点,并且也对React Hooks的使用有了更深一层的理解。
正文
概念
“SWR” 这个名字来自于 stale-while-revalidate
:一种由 HTTP RFC 5861 推广的 HTTP 缓存失效策略。这种策略首先从缓存中返回数据(过期的),同时发送 fetch 请求(重新验证),最后得到最新数据。
简单来说,就是,swr这个库会帮我们缓存get请求。并且封装成自定义hooks。看代码
1 | import useSWR from 'swr'; |
这样,可以把远程的数据也可以以hooks的形式写在代码里。业务代码中只需关心data或者error更新时,做什么操作。
解决了什么问题
业务开发中,我们常常会把代码拆分成很多细小的模块。如,A组件下有两个子组件B、C。
B和C都需要请求一个接口。那么以前的做法是必须要把这个接口提升到B、C共同的父组件A上,在useEffect里发起请求。用useState存储接口数据,然后再用props传递给B、C组件。
如果需要调接口的子组件很多、且层级很深。那么往往需要跨很多层组件调接口、传props,props太多,代码耦合度就高了,也会产生很多无用的代码。代码会越来越难以维护
如果接口放到子组件则会产生额外的请求。
swr如何解决的
swr可以把接口数据封装成hooks的形式,在需要的地方,插入一行代码即可注入。
还有一点,swr会缓存已经请求过的接口,所以该hooks被调用多少次、分散在多少个地方调用接口,都不会产生额外的请求。
post更新数据
useSWR只适合get请求。更新数据则应该需要一个编程的方式更新
1 | import useSWR, { useSWRConfig } from 'swr'; |
更多高级用法
更多牛逼的用法,贴个链接
- 乐观更新: 可以在发起更新请求时,乐观的直接更新本地数据。减少等待时间。
- 条件请求: 可以很智能的链式依赖的条件请求数据,捕获promise错误
- 自动重新请求: 这个有点酷了,自动重新请求,窗口获得焦点、网络重新连接时重新请求,可以使得应用及时获得最新数据。及时更新状态。
- 自动错误重试: 自动错误重试,不用处理错误
判断loading状态
useSWR不会直接返回loading状态。需要判断三种useSWR的三个返回值的状态来自行判断
三个返回值有这几种搭配
(注意是搭配,不是有这几种值)
1 | function App () { |
loading状态应该是data !== undefined && error === undefined
所以也有一个小小的限制。接口返回值不能是undefined
10月14日更新
其实想太多了,isValidating就是loading的意思。因为对于SWR来说,重新请求就是“校验”“对齐”数据。。
代数效应
2022年11月20日更新
代数效应首次遇见是卡颂的React技术揭秘里,里面的解释是:代数效应是函数式编程中的一个概念,用于将
副作用从
函数调用中分离。
如果这么理解的话,SWR就是一个把副作用抽离的一个很经典的方法。
在正常开发函数组件的过程中,遇到最多的副作用非调接口请求异步数据莫属。每次遇到这样的需求,往往如下写法:
1 | const [data, setData] = useState(); |
我们需要useEffect调用副作用代码,需要至少两个state来存储数据。
如果要去除这一块的副作用。需要抽离加载数据的逻辑为一个自定义hooks
1 | const [loading, data, error] = useFetch(fetchData) |
在于SWR,useFetch换成useSWR即可。
再后来,网络搜寻一番代数效应的含义。说实话更迷糊了。
网上几篇文章更多的是:利用一些新的思想,新的语法来解决当前的问题。
按我的理解,拿hooks来举例就是。
在hooks出来之前,函数组件只能是根据props的输入,来确定输出。f(props) = vdom。我们无法用一个合理的方式新增新的输入。一切其他输入都是副作用
1 | export default App(props) { |
React团队利用代数效应
,实现了hooks,来达到一种新的无副作用新增输入的方法:f(props + state) = vdom
1 | export default App(props) { |
照这么理解的话,SWR也是一种代数效应
。有了SWR就能实现f(props + state + remoteData) = vdom
1 | export default App(props) { |
React Hooks最佳实践
之前面试有被问过一个问题:Hooks与高阶组件有什么区别?我一脸懵逼,高阶组件不是一种组合方式吗、Hooks不是一套新的API,可以让函数组件存储数据吗?他们之间有毛关系?
现在我才彻底理解当时那个问题的含义。
他们本质上确实没有关系,但是两者都共同解决了一个问题。就是数据注入的问题。
关于React数据注入有props、context、高阶组件,现在多了一个Hooks。props与context都是最常规,最直接的数据注入,没啥好说。
高阶组件
高阶组件的数据注入最直观的是react-redux
的connect方法。connect方法把store里的数据直接注入到某一个组件。这种方式的缺点是,我们总需要去考虑数据是来自父组件还是connect注入的。两者冲突了还得特别处理。
还有就是,我们往往需要写不少代码来正确处理数据、ref。
hooks
hooks本质上也是一套新的数据注入的方式。最直观的也是react-redux
的useSelector
方法
我们要做的只是在需要数据的地方,插入一个自定义hooks,这个封装好的hooks会可靠的返回需要的数据,业务组件只需处理数据与视图的映射即可。
hooks的数据注入是可插拔的热更新试
注入,对代码结构0影响。也无需额外代码。是一种更佳的数据注入方案。
转念一想想,这不就是hooks这个单词的本意?