import React from "react";
import { useEffect, useState } from "react";
import ReactDOM from "react-dom";
const { unstable_batchedUpdates } = ReactDOM;
export default function Index() {
const [num, setNum] = useState(0);
const handleclick = () => {
setNum(num + 1);
setNum(num + 2);
}
console.log(num)
return <button onClick={handleclick}>{num}</button>;
}
这段代码的打印结果是:2
而
import React from "react";
import { useEffect, useState } from "react";
import ReactDOM from "react-dom";
const { unstable_batchedUpdates } = ReactDOM;
export default function Index() {
const [num, setNum] = useState(0);
const handleclick = () => {
setNum(num => num + 1);
setNum(num => num + 2);
}
console.log(num)
return <button onClick={handleclick}>{num}</button>;
}
这段代码打印结果是3
原因:
当你传入一个函数到 setNum 的时候,React 依然会进行批处理。这个函数被称为 "updater function",并且每次运行的时候都会获取到最新的状态值。
关键的不同在于,如果你传递一个值(如 setNum(num + 1)),那么 num + 1 就在当前的渲染周期中被计算了,而且不会随着状态的变化而变化。所以如果你在同一个事件处理函数中多次调用 setNum(num + 1),num 的值不会改变,你最终只会增加一次。
然而,如果你传递一个函数(如 setNum(prevNum => prevNum + 1)),那么这个函数会在每次更新时都被调用一次,而且每次都会拿到最新的状态值。所以即使在同一个事件处理函数中多次调用,它还是会每次都正确地增加状态。使用 updater 函数并不是跳过了 React 的批处理,而是确保了每次更新都基于最新的状态值。
换句话说,当你调用 setNum,React 不会立即改变 num 的值。相反,React 会把这个更新(即新的 num 值或者函数)放入一个队列中,稍后才会真正的去应用这个更新。
当 React 准备好去应用这些更新的时候(通常是在当前的 Javascript 执行栈完成后,例如事件处理函数执行完成之后),它会遍历这个队列,然后使用这些更新去更新状态,并且重新渲染组件。
当你传递一个函数给 setNum,这个函数会在更新应用的时候(也就是 React 真正改变状态的时候)被调用。在这个函数里,你会得到最新的状态值,这样你就可以根据最新的状态值去计算新的状态。