ste*_*bot 7 event-handling reactjs react-hooks
useEffect我理解和之间的区别,useLayoutEffect但我很好奇它是如何实现的。
我创建了这个沙箱,它显示了事情发生的顺序:
Log.js:
export default function Log(count, ref) {
console.log(`Synchronous ${count}: Ran after ${ref.current}`);
queueMicrotask(() =>
console.log(`Microtask ${count}: Ran after ${ref.current}`)
);
setImmediate(() => console.log(`Task ${count}: Ran after ${ref.current}`));
}
Run Code Online (Sandbox Code Playgroud)
App.scala:
import { forwardRef, useEffect, useLayoutEffect, useState } from "react";
import Log from "./Log";
const App = forwardRef((props, ref) => {
const [, setCount] = useState(0);
ref.current = "render";
Log(2, ref);
useLayoutEffect(() => {
ref.current = "useLayoutEffect";
});
Log(3, ref);
useEffect(() => {
ref.current = "useEffect";
});
Log(4, ref);
return (
<button
onClick={() => {
console.log("Click");
setCount((x) => x + 1);
}}
>
Click
</button>
);
});
export default App;
Run Code Online (Sandbox Code Playgroud)
index.js:
import React, { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";
import Log from "./Log";
const rootElement = document.getElementById("root");
const ref = React.createRef();
ref.current = "start";
Log(1, ref);
ReactDOM.render(
<StrictMode>
<App ref={ref} />
</StrictMode>,
rootElement
);
Log(5, ref);
Run Code Online (Sandbox Code Playgroud)
运行应用程序并单击按钮后,控制台显示:
Synchronous 1: Ran after start
Synchronous 2: Ran after render
Synchronous 3: Ran after render
Synchronous 4: Ran after render
Synchronous 5: Ran after useLayoutEffect
Microtask 1: Ran after useLayoutEffect
Microtask 2: Ran after useLayoutEffect
Microtask 3: Ran after useLayoutEffect
Microtask 4: Ran after useLayoutEffect
Microtask 2: Ran after useLayoutEffect
Microtask 3: Ran after useLayoutEffect
Microtask 4: Ran after useLayoutEffect
Microtask 5: Ran after useLayoutEffect
Task 1: Ran after useLayoutEffect
Task 2: Ran after useLayoutEffect
Task 3: Ran after useLayoutEffect
Task 4: Ran after useLayoutEffect
Task 2: Ran after useLayoutEffect
Task 3: Ran after useLayoutEffect
Task 4: Ran after useLayoutEffect
Task 5: Ran after useEffect
Click
Synchronous 2: Ran after render
Synchronous 3: Ran after render
Synchronous 4: Ran after render
Microtask 2: Ran after useLayoutEffect
Microtask 3: Ran after useLayoutEffect
Microtask 4: Ran after useLayoutEffect
Microtask 2: Ran after useLayoutEffect
Microtask 3: Ran after useLayoutEffect
Microtask 4: Ran after useLayoutEffect
Task 2: Ran after useEffect
Task 3: Ran after useEffect
Task 4: Ran after useEffect
Task 2: Ran after useEffect
Task 3: Ran after useEffect
Task 4: Ran after useEffect
Run Code Online (Sandbox Code Playgroud)
我注意到的第一件事是:
Synchronous 5: Ran after useLayoutEffect
Run Code Online (Sandbox Code Playgroud)
这表明它useLayoutEffect是在之前安排的微任务之前触发的。这意味着它不是作为微任务实现的,而必须是一些内部任务队列(这并不奇怪)。
接下来的事情是:
Task 4: Ran after useLayoutEffect
Run Code Online (Sandbox Code Playgroud)
由于useEffect让浏览器渲染并运行其他任务,我希望将其实现为一个任务,因此在下一个事件循环迭代中安排在任务 3 和 4 之间。
关于为什么它发生在任务 4 和 5 之间,我能想到的唯一解释是,React 正在创建一个任务,但不是在调用钩子时调度它,而是在内部对其进行排队,然后在渲染完成后创建一个任务执行该效果队列。
单击按钮后的下一个渲染会显示不同的内容:
Task 2: Ran after useEffect
Task 3: Ran after useEffect
Task 4: Ran after useEffect
Run Code Online (Sandbox Code Playgroud)
在这里,它似乎在实际调用钩子之前预先安排了任务来处理效果。
任何人都可以阐明它的实际工作原理吗?
奖金问题
严格模式导致组件每次渲染两次,这就是为什么我们看到以下重复条目:
Microtask 2: Ran after useLayoutEffect
Microtask 3: Ran after useLayoutEffect
Microtask 4: Ran after useLayoutEffect
Run Code Online (Sandbox Code Playgroud)
为什么这些没有重复的条目?
Synchronous 2: Ran after render
Synchronous 3: Ran after render
Synchronous 4: Ran after render
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
695 次 |
| 最近记录: |