swr把状态管理和ajax网络请求结合起来的库,类似的还有query-react(功能差不多).
可以down下本文示例代码,本地跑一跑更容易理解.
swr解决了什么痛点
假如我们有个需求,远程获取count值,并且提供个post请求更新count值.
在常规react项目中,我们需要哪些准备呢?
useEffect来开启初始化请求.loading的state,来标识加载中.AddLoading的state,来标识提交加载.count的state,保存请求来的数据.
代码如下:
import { getCount, addCount } from './api'
import { useEffect, useState } from 'react'
function App() {
const [loading, setLoading] = useState(false)
const [addLoading, setAddLoading] = useState(false)
const [count, setcount] = useState(0)
function getData() {
setLoading(true)
getCount().then(res => {
setcount(res)
}).finally(() => setLoading(false))
}
useEffect(() => {
getData()
}, [])
function onAdd() {
setAddLoading(true)
addCount().then(() => getData()).finally(() => setAddLoading(false))
}
return (
<div>
{
loading ? <p>加载中loading</p> : <p>{ count }</p>
}
<button onClick={onAdd}>{ addLoading ? '正常提交计算loading' : '点击+1'}</button>
</div>
)
}
用swr改造下代码
import useSWR from 'swr'
import { getCount, addCount } from './api'
function SwrApp() {
const { data: count, isLoading, mutate } = useSWR('getCount', getCount)
async function onAdd() {
await mutate(addCount, { optimisticData: count + 1, populateCache: true })
}
return (
<div>
{
isLoading ? <p>加载中loading</p> : <p>{ count }</p>
}
<button onClick={onAdd}>{'点击+1'}</button>
</div>
)
}
swr帮我们把useEffect/useState/loading逻辑封装在hook中,并且提供mutate方法,让我们去发送post请求,并且会自动请求get获取最新值.
关于乐观更新
swr示例中,并没有addLoading相关的逻辑,是因为swr提供了乐观更新的功能.
所谓乐观更新,就是当我们发送post后,不需要验证后端是否操作成功,而是直接更新视图,带来更丝滑的用户体验.
mutate方法第二个参数optimisticData就是手动设置更新后的值,给用户一种点击了立马就ok了的感觉,从而不需要提供新的loading表示网络还在请求中....
swr其他的一些功能
大概列举下个人认为使用频率较高的一些特性:
- 有序请求:假如我们快速切换
tab并且每一次切换都发送get请求,swr内部会处理逻辑,不会因为请求异步的原因导致tab内容显示错误. - 防止间隔极低的错误多余请求:假如页面有2个组件,都使用了
useSWR请求同一个接口,因为第一个参数key相同,swr会只发送第一次的网络请求,第二次的请求会通过缓存拿到,从而节省一次多余的网络请求. key值依赖:当useSWR第一个参数key带有state并变化时,触发请求.这个有什么用呢,举2个官网提供的例子:
// 依赖请求,只有当网络请求回来user信息时,才会走下一个请求.
const { data: user } = useSWR('/api/user')
const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
// 分页,执行setPageIndex就会触发请求
const [pageIndex, setPageIndex] = useState(0);
const { data } = useSWR(`/api/data?page=${pageIndex}`, fetcher);
- 提前加载数据,
swr提供了preload方法,可以在任何地方执行preload('api/user', fetcher),之后当我们第一次使用swr请求api/user接口时,不会走网络请求,而是拿到缓存的,从而达到急速显示的体验.
其他的一些功能,可以去swr官网看下.
总结
整体感觉swr并不难上手,难度不高.可以让代码简洁,并且对数据请求功能进行了加强,非常实用啊~