• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

react原理-transition概念

武飞扬头像
coderlin_
帮助1

在react18之中,引入了transition的概念。而且有一个新的api和两个新的hooks

  • startTransition
  • useTransition
  • useDeferredValue

场景应用:
比如通过输入框输入内容更新列表内容,对于用户来说,输入框输入之后立马反馈的优先级是高过于列表更新的优先级的。但是对于18之前的版本来说,更新没有分优先级,导致如果数据量大,列表更新慢,用户输入在输入框输入内容后很慢才能得到反馈,用户体验差。

而transition可以让列表更新的优先级降低,让用户输入的先处理,然后再处理列表更新。18之后开启了concurrent mode模式,更新也分了优先级的概念。

用法:

setData1(e)
startTransition(()=>{ 
	setData2(e)
})

将需要延迟更新的任务放到startTransition去执行,这样里面的更新任务就会被赋予transition的优先级。

setTimeout

setTimeout也有类似于延迟更新的效果,比如

setData1(e)
setTimeout(()=>{ 
	setData2(e)
}, 200)
  • 跟startTransition相比,startTransition的本质是,将任务的优先级降低,所以当用户一致输入的时候,优先级较低的任务,不会阻碍输入框的回显。并且transition的时机,是比setTImeout更加合适的,他会在没有搞优先级任务的情况下,第一时间处理。而setTimeout的时间是人为控制的,不够准确。
  • 第二则是,当渲染任务多的时候,setTImeout仍会阻碍搞优先级的任务,因为等延时时间一到,setTImeout里面的任务就会被执行,此时仍会阻止页面的交互。但是transition就不同了,在conCurrent mode下,react将该任务的优先级降低,等到浏览器空闲的时候才会执行。
  • 但也不是说startTransition的任务永远不会影响主流程,因为在react中,每个任务都有过期时间,而过渡任务的过期时间比紧急任务长了很多而已,但是当该过渡任务迟迟得不到处理,并且已经过期的时候,react就会先处理这个过期的过渡任务,然后再继续调度。具体可以了解react的schedlue模块。
防抖
  • 输入框的内容经常跟防抖节流打交道,但是其本质也是通过setTimeout,只不过控制了render的次数,而且防抖节流也需要人为的控制时间,而使用startTransition就不需要考虑这么多。

transition功能特性

transition顾名思义过度,状态更新的任务一般有两种,一种是紧急更新任务,比如用户交互行为,点击,输入等等。
而另一种则是过渡更新任务,比如上面列表的更新,这种任务的优先级低于紧急更新任务。

startTransition

startTransition(fn)

同步执行,但是fn里面的更新会被标记transition的优先级。也就是优先级更低了。

useTransition

startTransition只是用来降低优先级的,也就是过渡,但是过渡了多久我们需要一个状态来知道。useTransition就是用来做这个事情的。

const [isPending, startTransition] = useTransition()

startTransition(fn)

useTransition返回两个值,第一个就是是否正在过渡到控制变量,第二个就是跟startTransition用法一样的,用来降低任务优先级的函数。但任务处于过渡阶段的时候,isPending为true,告诉开发者,目前该任务正在过渡。

useDeferredValue

上述的startTransition和useTransition本质都是将一些任务的优先级降低。
而useDeferredValue可以让状态滞后更新。实现效果类似于transiton,当紧急的任务执行之后,再得到新的状态,而这个新的状态就是deferredValue。

跟useTransition的区别

同:内部实现一样,都是将任务标记为过渡更新任务。
别:

  • useTransition是将处理一段逻辑,将任务变为过渡任务,useDeferredValue是将原值通过过渡任务后得到新的值,他是产生一个新的状态。
  • 其次就是useDeferredValue的更新会更滞后于useTransition,因为内部是使用useEffect来调用startTranstion的。下面原理环节会讲到。

原理

startTransition

startTransition的源码实现

学新通
他的本质有点类似于17之前的事件更新,通过开关ReactCurrentBAtchConfig.transition
ReactCurrentBAtchConfig.transition默认值是null,再需要更新过渡任务的时候,将其置为{},这样startTransition里面的函数执行的时候,就会判断ReactCurrentBAtchConfig.transition以此来将其优先级降低。
学新通

useTransition

学新通
mount更新阶段,执行的函数是mountTransition,update阶段执行的函数是updateTransition
学新通
如图是mountTransition,本质很简单,就是通过调用mountState产生一个状态,然后通过startTransition绑定默认参数,调用moutnWorkInProgressHook创建hooks对象,跟其他hook链接,最后这个hooks.memoizedState保存的就是startTransition这个函数。

注意这里的startTransition跟上面的startTransition不一样,

学新通
如上,则是useTransition返回的第二个参数,本质就是先调用setPending(ture),然后切换transitiion上下文,让setPending(false)的更新也变成了过渡任务,这样setPending(false)和callback的任务优先级相同,他们会同时处理。

所以useTransition可以看成useState startTransition
学新通

useDeferredValue

学新通
学新通
useDeferredValue本质也是调用了useState useEffect,通过监听value值的改变,触发useEffect回调函数的更新,再去切换tranition上下文,更新setValue(value)
所以useDeferredValue可以看成:useState useEffect startTransition。
学新通

看看react如何通过判断transition上下文。

const [data, setData] = useState({})
startTransition(()=>setData({}))

一般startTransition里面函数,存在着触发更新的动作,比如useState的第二个参数setState,他们会创建update,更新优先级,开始调度。具体可以看hooks实现逻辑
所以重点看看产生update时候的优先级的处理,以setState为例子
useState的第二个参数,实际上是调用dispatchSetState函数
学新通
学新通
requestUpdateLane就是用来获取当前update的优先级的。来看具体实现
学新通
第一个判断就是判断是否是同步模式下,也就是18之前的模式,他不支持优先级的概念。

学新通

学新通学新通

其次就是判断是否是transition的上下文,判断方式也很简单粗暴,直接判断ReactCurrentBatchConfig.transition是否不等于null,是的话就表示处于transition的更新。
然后返回currentEventTransitionLane,也就是transition的优先级
学新通

学新通

这也就解释了通过切换transition上下文,产生的update的优先级并不一样。
然后处理这个update的时候
学新通
学新通
学新通
可以看到,setSe 产生的update的确走了这个逻辑,最后返回的优先级就是64。
然后将update插入hooks的update连表上,更新调用scheduleUpdateOnFiber开始新的一轮调度。
然后最后会执行ensureRootIsScheduled函数,该函数根据当前的优先级,调用schedule模块提供的schedule_callback函数调度任务。如下:
学新通

对于64的优先级,被分配到了normalPriority的优先级,
学新通
然后通过注册任务,开启调度。

自此,整个transition的流程就已经走通了。

总结:

  • transition过渡,就是将一些不紧要的任务降低其优先级,使其不阻塞高优先级的任务。

  • 具体实现就是通过切换transition上下文,使产生的udpate获取更低的优先级,这样调度的时候过期时间就会更长,从而不会阻塞高优先级的任务。

  •  

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgffkfk
系列文章
更多 icon
同类精品
更多 icon
继续加载