在v18之前,只有事件回调、生命周期回调中的更新会批处理,比如onClick。而在promise、setTimeout等异步回调中不会批处理,这就会导致多次render。React18实现了自动批处理,减少了更新次数,提升性能。
接下来,简单分析下setState例子,加深对批处理更新的理解。
const [myState,setMyState] = useState(1);
const [flag, setFlag] =useState(true);
console.log('render');
const handleClick = ()=>{
setMyState((myState) =>myState+6);
console.log('myState1',myState);
setMyState(myState+1);
setMyState((myState) =>myState+6);
console.log('myState2',myState);
setFlag((flag)=>!flag);
setTimeout(()=>{
setMyState(myState+1);
console.log('myState3',myState);
setMyState((myState) =>myState+10);
console.log('myState4',myState);
},1000)
}
return (
<p>
<button onClick={handleClick}>myState:{myState},flag:{flag?'true':'false'}</button>
</p>
)
点击按钮之后将输出:
render
myState1 1
myState2 1
render
myState3 1
myState4 1
render
按钮上显示变化myState:1,flag:true 到 myState:8,flag:false, 到 myState12,flag:false
setState是异步更新的,setState((pre)=>...)此种更新方式将会依赖上一次的状态值,多个state更新会进行批处理更新,减少渲染次数。
点击按钮之后,setState将会在队列中排队,先抛开setTimeout里面的setState,此时为
setMyState((myState) =>myState+6);
setMyState(myState+1);
setMyState((myState) =>myState+6);
setFlag((flag)=>!flag);
状态myState输出会先同步执行完,因为点击按钮时,当前状态中的myState为1,flag为true。所以输出两个myState3
队列中的setState,他们的上下文,作用域中myState为1,flag为true。
setMyState((myState) =>myState+6); 执行该更新会依赖上一个状态,上个状态为1,所以执行完后myState为7。
setMyState(myState+1); 这段很容易误解是7+1=8,其实不是。因为setState是异步的,当前队列里,它在寻找myState的值的时候,通过作用域找到的是状态的初始值1,所以该更新执行后myState变为2,即从7->2。
setMyState((myState) =>myState+6);执行这个状态更新的时候,它依赖上一个更新值,即2,所以这里的myState初始值为2,即从2->8。
最后是flag变为false。
此时按钮上显示的是myState:8,flag:false。
接着看setTimeout里的函数。同样的对列里是
setMyState(myState+1);
setMyState((myState) =>myState+10);
这里要注意,setTimeout整个函数式先执行的,回调会被放在宏任务里,它们的state的作用域是在click时候的状态下的上下文,即myState是1,flag是true。
setMyState(myState+1);,从1->2
setMyState((myState) =>myState+10); 从2->12。
按钮上显示myState12,flag:false。
在state变化过程当中,页面不会变化一次刷新一次,react框架层面会帮我们做批量更新。
有一点要注意:useState会形成闭包,setState是依赖执行更新状态时的值,而不是更新状态中的值(除setState(()=>{...}形式))。
React18引入了自动批处理机制,优化了异步回调中的更新,减少了渲染次数。本文通过实例分析了setState的批处理更新,解释了在不同场景下如何依赖上一次的状态值进行异步更新,以及useState的闭包特性。
2999

被折叠的 条评论
为什么被折叠?



