我已經使用 Javascript 作業了幾年,根據我目前對事件回圈的了解,我很難理解為什么這個來自 React 檔案的測驗配方有效。有人能夠準確地分解那里的每個步驟中發生的事情嗎?對我來說,這在測驗中起作用似乎很神奇:
await act(async () => {
render(<User id="123" />, container);
});
// expect something
組件看起來像這樣(復制以防鏈接被棄用):
function User(props) {
const [user, setUser] = useState(null);
async function fetchUserData(id) {
const response = await fetch("/" id);
setUser(await response.json());
}
useEffect(() => {
fetchUserData(props.id);
}, [props.id]);
if (!user) {
return "loading...";
}
return (
<details>
<summary>{user.name}</summary>
<strong>{user.age}</strong> years old
<br />
lives in {user.address}
</details>
);
}
渲染中沒有隱式或顯式回傳發生,那么行為如何知道等待組件中發生的異步內容(獲取等)?
對我來說,這更有意義:
await act(async () => render(<User id="123" />, container));
或(這是同一件事):
await act(async () => {
return render(<User id="123" />, container);
});
甚至:
await act(render(<User id="123" />, container));
但這似乎不是人們如何使用它,或者它打算如何使用,所以我有點迷茫。我見過與酶相同的例子mount。
我不想創建一個脆弱的測驗,所以我真的很想了解這一點。
它是否與異步回呼有關,即是否最后將某些內容附加到事件回圈中,從而使等待等待渲染中的所有內容在決議之前發生?
我在這里畫了一個空白,并在 react doc 叢林中掙扎,因為每個人似乎都在使用這種模式,但沒有人真正解釋它為什么或如何作業。
我在這里先向您的幫助表示感謝!
uj5u.com熱心網友回復:
當仔細查看 的源代碼時react-dom,react-dom/test-utils似乎使整個事情起作用的是在recursivelyFlushAsyncActWork 中的第一個效果重繪 之后發生的setImmediate 呼叫。
似乎act選擇使用 thisrecursivelyFlushAsyncActWork只是因為回呼具有“thenable”的簽名,即一個 Promise。你可以在這里看到這個。
這應該意味著發生的事情是(簡化)這個:
- 該
useEffect回呼重繪 (將fetch在事件回圈)。 - 該
setImmediate回呼“確保”我們的模擬諾言/訪解決。 - 第三次重繪 由
setImmediate回呼內部的遞回(由 呼叫enqueueTask)發生,使狀態更改出現在 DOM 中。 - 當沒有任何東西可以重繪 時,它會呼叫最外層
resolve和我們的act決心。
在看起來有點像這樣的代碼中(除了這是從react-dom我的 React 專案的 node_modules 中獲取的舊版本,現在flushWorkAndMicroTasks似乎被稱為recursivelyFlushAsyncActWork):
function flushWorkAndMicroTasks(resolve) {
try {
flushWork(); // <- First effect flush (fetch will be invoked by the useEffect?)
enqueueTask(function () { // <- setImmediate is called in here (finishes the fetch)
if (flushWork()) { // <- Flush one more time and the next loop this will be false
flushWorkAndMicroTasks(resolve);
} else {
resolve(); // <- resolve is called when flushWork has nothing left to flush.
}
});
} catch (err) {
resolve(err);
}
}
附加資訊(更新)
除非我弄錯了,否則這應該意味著await act(async () => { render(...); });“僅”等待第一個事件回圈。即如果你在你的模擬或 React 代碼中添加一個計時器或其他可能需要多個回圈來解決的東西,它不會被等待(如果我錯了,請糾正我!)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/344606.html
標籤:javascript 反应 异步 异步等待
