【发布时间】:2019-11-27 08:30:51
【问题描述】:
我有以下钩子:
const useBar = () => {
const [myFoo, setFoo] = useState(0);
const [myBar, setBar] = useState(0);
useEffect(() => {
setFoo(myFoo + 1);
console.log("setting foo (1)", myFoo, myBar);
}, [setFoo, myFoo, myBar]);
useEffect(() => {
setBar(myBar + 1);
console.log("setting bar (2)", myFoo, myBar);
}, [setBar, myBar, myFoo]);
};
在使用组件时,我有无限循环的预期行为:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const Bar = () => {
useBar();
return <div>Bar</div>;
};
function App() {
return (
<Bar />
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
来自console.log:
setting foo (1) 1 1
setting bar (2) 1 1
setting foo (1) 2 2
setting bar (2) 2 2
setting foo (1) 3 3
setting bar (2) 3 3
...
但是使用@testing-library/react-hooks 进行测试只给出第一个循环输出:
describe("Tests", () => {
test("useBar", async () => {
const { rerender } = renderHook(() => {
return useBar();
});
// await waitForNextUpdate();
// tried the above doesn't work
// rerender();
// with rerender it loops through the next "cycle"
});
});
想知道如何在不调用 rerender 的情况下正确测试钩子并模仿与 React 相同的行为 - 在状态更改时重新渲染组件。
【问题讨论】:
-
您能否提供一个工作示例来说明您想要实现的目标?在您当前的示例中,您最终会得到一个无休止的更新“循环”,这会减慢 UI 的速度。我通过使用
act助手实现了你正在做的事情的变体:codesandbox.io/s/ecstatic-ardinghelli-hsctu(请记住,这是一个人为的例子)。 -
我不熟悉
@testing-library/react-hooks,但正如西蒙所说,您是否尝试过使用来自react-dom/test-utils的act 构建它? -
我不明白你为什么要使用两个useEffect和next,为什么要将setBar函数放入数组依赖中?
-
@SimonIngeson 有许多实用的钩子,其中包括不止一个
useEffect。我把无限循环放在那里,因为有时你的钩子可能会因为这种效果而进入无限循环,而且你可能想测试这不会发生。另一方面,当使用react-hooks-testing-library进行测试时,带有 2+useEffect的钩子无法正确执行,这就是我提出问题的原因。如果你觉得这个例子不合逻辑,请尝试思考:“How to test that a hook is not running an infinite loop, due to interdependentuseEffect” -
@dinchev 是的,我知道,但在依赖数组中,您只能放置变量、对象、数组来进行浅层检查,是否需要重新运行渲染。你不能用函数进行浅层检查
标签: reactjs react-testing-library react-hooks-testing-library