大家好,我是Kason。React18已经进入RC(releasecandidate)阶段,距离正式版仅一步之遥。V18增加了许多新特性。今天我们不说新特性,说说v18比老版本更好的一个细节:v18中,组件渲染的数量可能会少一些。欢迎加入人类优质前端框架群,飞行状态从何而来?在以下组件中:functionApp(){const[num,update]=useState(0);//...省略}App组件渲染完成后会执行useState,返回num的最新值。换句话说,组件必须渲染才能知道最新状态。为什么会这样?考虑以下代码触发更新:const[num,update]=useState(0);constonClick=()=>{更新(100);更新(num=>num+1);update(num=>num*3);}onClick执行后,触发update,update导致App组件渲染,然后执行useState。在useState中,num将按如下方式计算:update(100)changesnumto100update(num=>num+1)changesnumto100+1=101update(num=>num*3)changesnumto101*3=303即App组件渲染时,num为303。因此state的计算需要先收集触发的更新,然后在useState中统一计算。对于上面的例子,更新分别命名为u0~u2,state的计算公式为:baseState->u0->u1->u2=newState并发变化Concurrent(并发)给React带来了优先级的概念,体现出来在状态计算中,更新根据触发更新的场景有不同的优先级(例如onClick回调中触发的更新比useEffect回调中触发的更新具有更高的优先级)。计算状态所表达的差异是,如果更新具有低优先级,它将被跳过。假设上例中u1优先级低,当App组件渲染时,计算num状态的公式为://其中u1因为优先级低被跳过baseState->u0->u2=newState即就是:update(100)将num变成100update(num=>num*3)把num改成100*3=300显然这个结果是错误的。因此在并发情况下,React计算状态的逻辑会更加复杂。具体来说,它可能包含多轮计算。在计算状态时,如果跳过了一次更新,则下一次计算将从跳过的更新开始继续。例如,在上面的例子中,u1被跳过了。当跳过u1时,num为100,此时的状态100,以及u1和后续的所有更新都会被保存起来,参与下一次的计算。在示例中,它为u1和u2保存。下次更新的情况如下:初始状态为100,update(num=>num+1)改变num为100+1=101update(num=>num*3)改变num为101*3=303是可见的,finally303的结果和同步React是一致的,但是需要渲染两次。同步React渲染一次,结果为303。并发React渲染两次,结果为300(中间状态)和303(最终状态)。新旧Concurrent的区别从上面的例子我们发现,组件渲染的次数受跳过更新次数的影响。事实上,它可能不仅渲染两次,而是多次。在旧版本的并发React中,优先级是一个名为expirationTime的时间戳。比较是否应该跳过更新的算法如下://更新优先级是否低于渲染优先级if(updateExpirationTime
