为什么 React 需要调用两次 requestAnimationFrame

103 阅读1分钟

React 中,如何在 setState 之后调用某些函数执行操作,比如我用 reactflow.dev/ 设置了节点和边,然后想调用 fitView 让页面自适应。

我就会这样写代码,但是设置了一个 requestAnimationFrame。

setNodes([...layoutedNodes]);
setEdges([...layoutedEdges]);
requestAnimationFrame(() => {
 fitView();
});

要想生效的使用两个 requestAnimationFrame,或者使用 setTimeout。

setNodes([...layoutedNodes]);
setEdges([...layoutedEdges]);
requestAnimationFrame(() => {
	requestAnimationFrame(() => {
		fitView();
	});
});

这是为什么呢,我们来看看原因。

浏览器的渲染流水线是这样的:

https://webperf.tips/tip/browser-rendering-pipeline/

setState 之后, React 会在下次更新,过程有点类似 useEffect,看看 useEffect 的渲染更新时间,useEffect 会在浏览器的重绘之后执行。

https://x.com/_georgemoller/status/1628047165850365953

requestAnimationFrame 的渲染是这样的,下图的 rAf

https://medium.com/@paul_irish/requestanimationframe-scheduling-for-nerds-9c57f7438ef4

整合一下就这样的:

image.png

原来 requestAnimationFrame 先于 React 的更新执行,第一次没效果所以需要执行两次,等待 React 更新完之后。

为什么 setTimeout 是有效的,因为 setTimeout 是一个任务,会放在任务队列中,等主线程任务执行完才会执行,React 的更新就是在主线程的,所以说白了就是等 React 更新完之后再执行 setTimeout,这就是 setTimeout 为什么会生效。

image.png

参考资料: