gpt4 book ai didi

javascript - 为什么这个使用 await/act/async 的官方 React 测试配方真的有效?

转载 作者:行者123 更新时间:2023-12-04 12:52:59 26 4
gpt4 key购买 nike

我已经使用 Javascript 几年了,以我目前对事件循环的了解,我很难理解为什么 this testing recipe来自 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>
);
}
渲染上没有隐式或显式返回,那么 act 如何知道等待组件中发生的异步内容(获取等)?
对我来说,这会更有意义:
await act(async () => render(<User id="123" />, container));
或(这是同一件事):
await act(async () => {
return render(<User id="123" />, container);
});
甚至:
await act(render(<User id="123" />, container));
但这似乎不是人们如何使用它,或者它是如何被使用的,所以我有点迷茫。我见过 enzyme 的相同例子 mount .
我不想创建一个脆弱的测试,所以我真的很想了解这一点。
它是否与异步回调有关,即最后是否将某些内容附加到事件循环中,从而使等待等待渲染中的所有内容在解析之前发生?
我在这里画了一个空白,在 react doc 丛林中挣扎,因为 大家 似乎使用这种模式,但没有人真正解释它为什么或如何工作。
我在这里先向您的帮助表示感谢!

最佳答案

仔细查看 react-dom 的源代码时和 react-dom/test-utils似乎是什么让整个事情成功的是this setImmediate callrecursivelyFlushAsyncActWork 中的第一次效果刷新之后发生.
好像是 act选择使用这个recursivelyFlushAsyncActWork仅仅因为回调具有“thenable”的签名,即 Promise。你可以看到这个here .
这应该意味着发生的事情是(简化的):

  • useEffect回调被刷新(将 fetch 放在事件循环中)。
  • setImmediate回调“确保”我们的模拟 promise/fetch 得到解决。
  • 第三次刷新通过 setImmediate 内的递归发生。回调(由 enqueueTask 调用)使状态更改出现在 DOM 中。
  • 当没有东西可以冲洗时,它会调用最外面的 resolve和我们的act解决。

  • 在看起来有点像这样的代码中(除了这是从我的 React 项目的 node_modules 的旧版本 react-dom 中获取的,现在 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(...); }); "only"等待一个事件循环,除非最新刷新添加了新任务。 IE。如果两者之间存在刷新,则可以递归地添加 promise ,诸如 promise 链之类的微任务也可能会在第一个循环期间解决(因为它们在技术上是“阻塞”( source))。
    这意味着如果您在模拟或 React 代码中添加一个计时器或其他可能自然需要多个循环来解决的代码,则不会等待它,因为在解析之前没有捕获“after”事件,因为 then 监听器没有附加/回到了外在的 promise (如果我错了,请纠正我!)。

    关于javascript - 为什么这个使用 await/act/async 的官方 React 测试配方真的有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69775101/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com