hook中的useState连续多次更新 render渲染几次?
初学react 第一次点击minus事件和第二次点击事件的执行顺序不一致,setNum是异步的,为什么第一次先执行setNum,而不是执行 console.log("minus") ?
useState执行一次set就触发render,为什么多次执行set结果也只触发一次render?
烦请有空的大佬帮忙看一下!
const [num, setNum] = useState(1);
const minus = () => {
setNum(prev =>{
console.log(1);
return prev + 1
})
setNum(prev => {
console.log(2);
return prev + 1;
})
console.log("minus");
}
return (
<View className='container'>
<Text className="name">num:{num}</Text>
<Button onClick={minus}>计数</Button>
</View>
)
代码结果:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
(1) setNum是异步的吗?为什么多次setNum只render了一次
setNum并不是异步的,setNum可以为理解为scheduleUpdateOnFiber,他为一个fiber节点调度更新时是同步的,但是他调度的更新并不是立马执行的而是会推迟到微任务中一并之前所有调度了的更新,这也就是为什么多次setNum只render一次的原因,因为多次update会被reduce成一个,具体原理可以看这里我在其中写了一个简易的react batching逻辑
(2) 为什么首次以会先打印1,而后面几次不会
首先我们得知道react更新的逻辑,每个fiber上都存有一个lanes(一个32位有符号整数,用来当作BitSet使用),如果他大于零就代表他需要进行调度更新,或者需要清除lanes,当第一次渲染完成时fiber并没有额外的更新,所以他的lanes为0,当lanes为零是setNum会直接走优化逻辑,直接算出下一次的state,也就在这时调用了setNum第一个参数里的函数,这就是
1
在minus
之前打印的原因,在计算出下一次的state后会和当前的state进行比较如果发现前后state变化了的话,就会继续调度该更新,如果没变在比较后,就能直接return什么都不用干了。注意一旦调度成功,就会在fiber数上留下lanes,所以后续几次的setNum就不会走这个优化逻辑,所以minus
一直是最先打印的,因为setNum里面的函数是放在微任务中的(3) 如何让打印信息符合预期
知道了原理,我们要让他每次都打印的一样就很简单了,如果我们能保证setNum调用时fiber上的lanes为零就一直都会走优化逻辑,所有打印也就都一样了,那们要如何清除lanes呢,我们上面说过
如果一个fiber上的lanes大于零就代表他需要进行调度更新,或者需要清除lanes
如果一个setState调度了一次更新,但是他传入的nextState和当前的没有发生变化,那么就会在这轮更新中将该fiber上的lanes清除,考虑以下代码,如果在每次点击计数
之前都先点击一下reset fiber lanes
按钮就能保证setNum调用时fiber上的lanes总是空的那么他的打印永远都只会是详情信息可以看我对react更新时fiber树上lanes变化的分析
更多react原理可以查看我的项目tiny-react