演示:https://stackblitz.com/edit/vitejs-vite-nfngmd?file=src%2Fcom...
点最底部按钮:1 和 2,文件名 /src/com/TestCom.tsx
先看一段简单的代码:
console.log(1);
setTimeout(() => console.log(2), 0);
new Promise((resolve) => {
console.log(3);
resolve(4);
}).then((num) => console.log(num));
setData(() => {
console.log(5);
return { a: Date.now() };
});
console.log(6);
这段顺序执行如下:
- 1、3、6,是上下文
- 4、5,是微任务
- 2 是宏任务
也就是:1、3、6、4、5、2
现在代码不变将其全部包裹在 setTimeout
这个宏任务里
setTimeout(() => {
// 上面的代码
}, 0);
这个时候发现 setState
是最后执行,即:1、3、6、4、2、5
在上面演示中 TestCom.tsx
中有两个方法:clickHandle
和 clickTimeooutHandle
- 最终都是执行
clickHandle
- 不同的是
clickTimeooutHandle
将clickHandle
包裹在setTimeout
中执行
这里会有 2 个不同点
第一个不同:只点按钮 1,初始化和之后每次点击不同
- 初始化输出:1、3、5、6、4、2
- 之后每次点:1、3、6、4、5、2
第二个不同:按钮 1 和按钮 2 不同
- 按钮 1:1、3、6、4、5、2
- 按钮 2:1、3、6、4、2、5
请问这是怎么回事呢?
第一次点击和之后点击不同是因为 react 更新策略的原因,可以参考:
关于React FC useState,如何解释以下console.log?
按钮 1 和按钮 2 输出不同是因为 setState 执行环境不同,直接在事件处理回调函数中执行和在 setTimeout 回调函数中执行会有不同的行为,参考:
一文搞懂React 的 setState 机制