Heim > Fragen und Antworten > Hauptteil
useEffect(() => { console.log("render"); }); const handleClick = () => { setC1((c) => c + 1); Promise.resolve().then(() => { setC1((c) => c + 1); }); }; const handleClick2 = () => { Promise.resolve().then(() => { setC1((c) => c + 1); }); setC1((c) => c + 1); };
Warum erfolgt in der React18-Version nur ein Rendering, wenn auf die handleClick
方法会出现两次渲染,而点击handleClick2
-Methode geklickt wird?
Ich möchte, dass die Ausgabe beider Methoden gleich ist. Kann mir jemand sagen, warum sie unterschiedlich sind?
P粉6429205222023-09-08 17:06:21
我将解释这些调用顺序有何不同,以及观察到的行为如何可能。
我无法确切地告诉你 React 内部是如何批量更新状态的, 我只是假设 React 进行了复杂的优化,这与使用 React 的开发人员无关,并且需要深入了解 React 内部,甚至可能从一个版本更改为另一个版本。 (请随时纠正我。)
Promise.resolve()
安排一个新的微任务,实际上相当于 window.queueMicrotask()
。
setState
函数(可能)还会安排一个新的微任务,
因此它们的回调(Promise
和 setState
)都是在同一执行阶段调用的。
这两个变体的区别在于
handleClickA
中,在两个 updater
函数之间调用 setState2
挂钩,而handleClickB
中,两个 updater
函数都会直接依次调用。我稍微重写了您的代码,以更好地说明调用顺序:
const setState1 = setState; const setState2 = setState; const update1 = updaterFunction; // c => c + 1 const update2 = updaterFunction; // c => c + 1 const handleClickA = () => { // Scheduled functions: setState1( update1 ); // 1. --> [ update1 ] queueMicrotask(() => { // 2. --> [ update1, setState2 ] setState2( update2 ); // 4. --> [ update2 ] }); // update1(); // 3. --> [ setState2 ] // setState2( update2 ); // 4. --> [ update2 ] // update2(); // 5. --> [] }; const handleClickB = () => { // Scheduled functions: queueMicrotask(() => { // 1. --> [ setState2 ] setState2( update2 ); // 3. --> [ update2 ] }); setState1( update1 ); // 2. --> [ setState2, update1 ] // setState2( update2 ); // 3. --> [ update1, update2 ] // update1(); // 4. --> [ update2 ] // update2(); // 5. --> [] };
这里我说明了调用顺序。
(FIFO >):
handleClickA
:
// 0. --> [] - schedule update1 (setState1()) // 1. --> [ update1 ] - schedule setState2 // 2. --> [ update1, setState2 ] - invoke update1() // 3. --> [ setState2 ] - schedule update2 (setState2()) // 4. --> [ update2 ] - invoke update2() // 5. --> []
handleClickB
:
// 0. --> [] schedule setState2 // 1. --> [ setState2 ] schedule update1 (setState1()) // 2. --> [ setState2, update1 ] schedule update2 (setState2()) // 3. --> [ update1, update2 ] invoke update1() // 4. --> [ update2 ] invoke update2() // 5. --> []
我假设 React 尝试对当前排队的所有 updater
函数进行批处理。
即只要仅调用更新器函数,请尝试将它们批处理在一起并仅更新一次最终状态。
但是,如果调用了新的 setState
函数,React 可能会完成当前更新循环,并在调用下一个 updater 之前启动新的渲染周期代码> 函数。
我只能猜测为什么要这样做
setState
可能会以某种方式破坏批处理,或者setState
调用,下一次渲染将会延迟太多,或者