ahooks源码解析系列文章之定时器
本篇文章是ahooks源码解析系列文章的第七篇,主要总结以下几点:

- 巩固React Hooks的理解。
- 学习如何抽象自定义Hooks,构建属于自己的React Hooks工具库。
- 培养阅读学习源码的习惯,工具库是一个对源码阅读不错的选择。
注:本系列对ahooks的源码解析是基于v3.3.13。我自己folk了一份源码,主要是对源码做了一些解读,可见详情。
使用useInterval和useTimeout替代setInterval和setTimeout
下面介绍两个Hooks,即useInterval和useTimeout。它们的功能对应的是setInterval和setTimeout,那它们有什么优势呢?
先看useInterval:
function useInterval(
fn: ()=> void,
delay: number | undefined,
options?: {
immediate?: boolean;
},
){
const immediate = options?.immediate;
const fnRef = useLatest(fn);
useEffect(() => {
// 省略部分代码...
// 立即执行
if (immediate) {
fnRef.current();
}
const timer = setInterval(() => {
fnRef.current();
}, delay);
// 清除定时器
return () => {
clearInterval(timer);
};
// 动态修改 delay 以实现定时器间隔变化与暂停。
}, [delay]);
}
其区别如下:
- 可以支持第三个参数,通过immediate能够立即执行我们的定时器。这样就可以在变更delay的时候,会自动清除旧的定时器,并同时启动新的定时器。
- 通过useEffect的返回清除机制,开发者不需要关注清除定时器的逻辑,避免内存泄露问题。
useTimeout跟useInterval很类似,这里不再赘述。主要需要注意的是,这两个Hooks代替了setInterval和setTimeout,具有更好的兼容性和更好的内存管理问题。在开发过程中,一定要记得及时清除定时器。
使用requestAnimationFrame替代setTimeout和setInterval
setTimeout和setInterval常常会出现一些问题,比如间隔时间不准确、在页面不可见的时候可能无法执行、不同浏览器之间差异大等问题。因此,为了解决这些问题,我们可以使用requestAnimationFrame。
window.requestAnimationFrame()告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。为了提高性能和电池寿命,因此在大多数浏览器里,当requestAnimationFrame()运行在后台标签页或者隐藏的<iframe>里时,requestAnimationFrame()会被暂停调用以提升性能和电池寿命。
ahooks中也提供了使用requestAnimationFrame进行模拟定时器处理的hook,我们一起来看下:
useRafInterval和useRafTimeout
直接看useRafInterval。(useRafTimeout和useRafInterval类似,这里不展开细说):
function useRafInterval(
fn: () => void,
delay: number | undefined,
options?: {
immediate?: boolean;
},
){
const immediate = options?.immediate;
const fnRef = useLatest(fn);
useEffect(() => {
// 省略部分代码...
const timer = setRafInterval(() => {
fnRef.current();
}, delay);
// 清除定时器
return () => {
clearRafInterval(timer);
};
}, [delay]);
}
上述代码中展示出,跟前面的useInterval大部分代码逻辑都是一样的,但不同的就是定时使用了setRafInterval方法,清除定时器用了clearRafInterval。
setRafInterval方法中,判断是否支持requestAnimationFrame,如果不支持则依旧使用setInterval。初始记录一个start的时间。在requestAnimationFrame回调中,判断现在的时间减去开始时间有没有达到间隔,假如达到则执行我们的callback函数。更新开始时间。
const setRafInterval = function (callback:()=>void, delay:number = 0):Handle{
if (typeof requestAnimationFrame === typeof undefined) {
// 如果不支持,还是使用 setInterval
return {
id: setInterval
原创文章,作者:小编小本本,如若转载,请注明出处:https://www.benjiyun.com/yunzhujiyunwei/vps-yunwei/7294.html
