- 作者:老汪软件技巧
- 发表时间:2024-09-21 15:01
- 浏览量:
在react中, setState的实现复杂很多,分为同步任务(Sync lane)和普通任务(default lane),当我们在点击一个按钮的时候,同步调用state的时候就是同步任务,这个时候更新是一个微任务更新(会尽可能早的执行完更新,这个是react的一个优化,react任务鼠标等时间对于视图的更新是很急切的),而在包裹setTimeout和promise的setState,则更新lane为default lane 此时是一个宏任务更新。
急切更新
下面一个例子中,当点击按钮时会产生一个Sync lane的更新如下
import React, { useState } from 'react';
function App () {
const [count, setCount] = useState(0)
console.log('render')
const onClick = () => {
setCount((prev) => prev + 1)
setCount((prev) => prev + 1)
setCount((prev) => prev + 1)
}
return (
<div>
<div>{count}div>
<button onClick={onClick}>Incrementbutton>
div>
);
}
export default App;
源码我这就补贴了,感觉看起来很枯燥,这里我直接上图
在控制台中,我们会发现,render只打印了一次。
这个时候有的同学会说:react17也只打印一次。的确是,这里确实表现是一样的,但是接下来的代码就有所区别了
普通更新
import React, { useState } from 'react';
function App () {
const [count, setCount] = useState(0)
const onClick = () => {
+ setTimeout(() => {
setCount((prev) => prev + 1)
setCount((prev) => prev + 1)
setCount((prev) => prev + 1)
+ }, 0)
}
return (
{count}
);
}
export default App;
运行上面的代码,你会发现,在react17中,会打印三次,关于为何三次,我看了下源码是因为setTimeout等异步函数,会跳出了批处理的更新范围,导致后面每次调用都会触发重新渲染
注意:react 17中需使用传统的 ReactDOM.render的形式渲染,如果使用createRoot的形式,表现跟react18一致
在react18中,没有采用状态标识是否批量更新,而是仍然采用任务调度的形式,对于异步任务里的 setState, 将会产生一个 default lane的更新,该更新被react任务不是很紧急的更新,会采用宏任务来调度
不同的地方为粉色区域,基本流程和上面同步差不多,知识任务的优先级不同