• 作者:老汪软件技巧
  • 发表时间: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任务不是很紧急的更新,会采用宏任务来调度

不同的地方为粉色区域,基本流程和上面同步差不多,知识任务的优先级不同