书签 分享 收藏 举报 版权申诉 / 11

类型Hooks取数swr源码.docx

  • 文档编号:8961222
  • 上传时间:2023-02-02
  • 格式:DOCX
  • 页数:11
  • 大小:21.46KB
}>

);

}

2.9错误处理

onErrorRetry可以统一处理错误,包括在错误发生后重新取数等:

useSWR(key,fetcher,{

onErrorRetry:

(error,key,option,revalidate,{retryCount})=>{

if(retryCount>=10)return;

if(error.status===404)return;

//retryafter5seconds

setTimeout(()=>revalidate({retryCount:

retryCount+1}),5000);

}

});

3精读

3.1全局配置

在Hooks场景下,包装一层自定义Context即可实现全局配置。

首先SWRConfig本质是一个定制ContextProvider:

constSWRConfig=SWRConfigContext.Provider;

在useSWR中将当前配置与全局配置Merge即可,通过useContext拿到全局配置:

config=Object.assign({},defaultConfig,useContext(SWRConfigContext),config);

3.2useSWR的一些细节

从源码可以看到更多细节用心,useSWR真的比手动调用fetch好很多。

兼容性

useSWR主体代码在useEffect中,但是为了将请求时机提前,放在了UI渲染前(useLayoutEffect),并兼容了服务端场景:

constuseIsomorphicLayoutEffect=IS_SERVER?

useEffect:

useLayoutEffect;

非阻塞

请求时机在浏览器空闲时,因此请求函数被requestIdleCallback包裹:

window["requestIdleCallback"](softRevalidate);

softRevalidate是开启了去重的revalidate:

constsoftRevalidate=()=>revalidate({dedupe:

true});

即默认2s内参数相同的重复取数会被取消。

性能优化

由于swr的data、isValidating等数据状态是利用useState分开管理的:

let[data,setData]=useState(

(shouldReadCache?

cacheGet(key):

undefined)||config.initialData

);

//...

let[isValidating,setIsValidating]=useState(false);

而取数状态变化时往往data与isValidating要一起更新,为了仅触发一次更新,使用了unstable_batchedUpdates将更新合并为一次:

unstable_batchedUpdates(()=>{

setIsValidating(false);

//...

setData(newData);

});

其实还有别的解法,比如使用useReducer管理数据也能达到相同性能效果。

目前源码已经从unstable_batchedUpdates切换为useReducer管理

dispatch(newState);

3.3初始缓存

当页面切换时,可以暂时以上一次数据替换取数结果,即初始化数据从缓存中拿:

constshouldReadCache=config.suspense||!

useHydration();

//stale:

getfromcache

let[data,setData]=useState(

(shouldReadCache?

cacheGet(key):

undefined)||config.initialData

);

上面一段代码在useSWR的初始化期间,useHydration表示是否为初次加载:

letisHydration=true;

exportdefaultfunctionuseHydration():

boolean{

useEffect(()=>{

setTimeout(()=>{

isHydration=false;

},1);

},[]);

returnisHydration;

}

3.4支持suspense

Suspense分为两块功能:

异步加载代码与异步加载数据,现在提到的是异步加载数据相关的能力。

Suspense要求代码suspended,即抛出一个可以被捕获的Promise异常,在这个Promise结束后再渲染组件。

核心代码就这一段,抛出取数的Promise:

throwCONCURRENT_PROMISES[key];

等取数完毕后再返回useSWRAPI定义的结构:

return{

error:

latestError,

data:

latestData,

revalidate,

isValidating

};

如果没有上面throw的一步,在取数完毕前组件就会被渲染出来,所以throw了请求的Promise使得这个请求函数支持了Suspense。

3.5依赖的请求

翻了一下代码,没有找到对循环依赖特别处理的逻辑,后来看了官方文档才恍然大悟,原来是通过try/catch并巧妙结合React的UI=f(data)机制实现依赖取数的。

看下面这段代码:

const{data:

user}=useSWR("/api/user");

const{data:

projects}=useSWR(()=>"/api/projects?

uid="+user.id);

怎么做到智能按依赖顺序请求呢?

我们看useSWR取数函数的主体逻辑:

constrevalidate=useCallback(

async()=>{

try{

//设置isValidation为true

//取数、onSuccess回调

//设置isValidation为false

//设置缓存

//unstable_batchedUpdates

}catch(err){

//撤销取数、缓存等对象

//调用onError回调

}

},

[key]

useIsomorphicLayoutEffect(

()=>{

....

},

[key,revalidate,...]

每次渲染的时候,SWR会试着执行key函数(例如()=>"/api/projects?

uid="+user.id),如果这个函数抛出异常,那么就意味着它的依赖还没有就绪(user===undefined),SWR将暂停这个数据的请求。

在任一数据完成加载时,由于setState触发重渲染,上述Hooks会被重选执行一遍(再次检查数据依赖是否就绪)然后对就绪的数据发起新的一轮请求。

另外对于一些正常请求碰到error(shouldRetryOnError默认为true)的情况下,下次取数的时机是:

constcount=Math.min(opts.retryCount||0,8);

consttimeout=

~~((Math.random()+0.5)*(1<

重试时间基本按2的指数速度增长。

所以swr会优先按照并行方式取数,存在依赖的取数会重试,直到上游Ready。

这种简单的模式稍稍损失了一些性能(没有在上游Ready后及时重试下游),但不失为一种巧妙的解法,而且最大化并行也使得大部分场景性能反而比手写的好。

4总结

笔者给仔细阅读本文的同学留下两道思考题:

•关于Hooks取数还是在数据流中取数,你怎么看呢?

•swr解决依赖取数的方法还有更好的改进办法吗?

配套讲稿:

如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。

特殊限制:

部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。

关 键  词:
Hooks swr 源码
提示  冰豆网所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
关于本文
本文标题:Hooks取数swr源码.docx
链接地址:https://www.bdocx.com/doc/8961222.html
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2008-2022 冰点文档网站版权所有

经营许可证编号:鄂ICP备2022015515号-1

收起
展开