当前位置: 首页 > Web前端 > HTML

React是如何原生实现防抖的?

时间:2023-03-28 00:28:04 HTML

大家好,我是Kason。作为前端,你一定熟悉debounce和throttle的概念。在React18中,基于新的并发特性,React原生实现了防抖功能。今天我们就来说说这是如何实现的。欢迎加入人类优质前端框架群。UseTransitionDemouseTransition是一个新的原生Hook,用于执行一些优先级较低的更新。在我们的Demo中,有ctn和num两种状态,其中控制ctn和输入框的内容。当触发输入框的onChange事件时,会同时触发ctn和num的状态变化。触发num状态变化的方法(即updateNum)被包裹在startTransition中:functionApp(){const[ctn,updateCtn]=useState('');const[num,updateNum]=useState(0);const[isPending,startTransition]=useTransition();return(

{updateCtn(value);startTransition(()=>updateNum(num+1))}}/>
);}num将作为props传递给BusyChild组件。通过while循环人为增加BusyChild中componentrender消耗的时间:constBusyChild=React.memo(({num}:{num:number})=>{constcur=performance.now();//增加时间ofrender耗时while(performance.now()-cur<300){}return
{num}
;})因此,在输入框输入内容时,可以明显感觉到卡顿。网上的例子地址应该是在onChange中同时触发ctn和num的状态变化,并且它们在视图中的显示应该是同步的。但实际上,在输入框连续输入一段文字后(即在视图中连续显示ctn的状态变化),num只会变化一次。如下图,初始输入框没有内容,num为0:输入框输入长文本后,num变为1:这个效果就像:startTransition包裹的update有防抖效果.这怎么可能?什么是车道?React18有一套更新优先级机制,不同地方触发的更新有不同的优先级。优先级的定义基于用户感知。比如用户不希望输入框的文字卡住,那么onChange事件中触发的更新是同步优先级(最高优先级)。等待时间,所以useEffect中触发的update是默认的优先级,那么优先级怎么表示呢?使用称为lane的31位二进制文??件。例如同步优先级和默认优先级定义如下:constSyncLane=0b000000000000000000000000000001;constDefaultLane=0b0000000000000000000000000010000;值越小,优先级越高,即SyncLane{updateCtn(value);startTransition(()=>updateNum(num+1))}其中:updateCtn(value)在onChange中触发,优先级为SyncLaneupdateNum(num+1)。因为是在startTransition中触发的,所以priority是TransitionLanes之一。当在输入框中重复输入文本时,上面的过程会重复执行,不同的是:SyncLane会被执行,因为它的优先级最高,所以我们会看到输入框中的内容发生了变化。TransitionLanes相关的lane优先级低于SyncLane,暂时不会执行。同时,他们会纠缠不清,阻止一个update因为优先级太低,一直无法执行。React有一个过期机制:每次更新都有一个过期时间。如果在到期时间内没有执行,它就会过期。过期的更新会被同步执行(也就是说他的优先级变得和SyncLane一样)。在我们的示例中,startTransition(()=>updateNum(num+1))会生成很多纠缠不清的TransitionLanes相关车道。一段时间后,其中一个通道到期,因此其优先级提高到与SyncLane相同,并立即执行。又因为这个lane和其他TransitionLanes相关的lanes纠缠在一起,所以会一起执行。表现为:在输入框不停地打字,但是视图中num显示的数字过一会就变了。总结今天我们讲了useTransition的一些内部实现,涉及:lane模型纠缠机制更新过期机制最有意思的是由于不同电脑的性能不同,浏览器的帧率会发生变化,所以React会动态调整不同电脑的防抖效果。这相当于不需要你手动设置debounce的时间参数,React会根据电脑的性能动态调整。