为什么解构需要waitFor?
Codesandbox
所有的测试都做同样的事情。在'ok.test.ts'文件我使用renderHook,我使用result.current[1]
来设置状态和result.current[0]
来获取状态的值,到目前为止一切顺利。
react-hooks-testing-library
作者在此
TL,博士;你不能解构result.current
而让get
接收更新的值。
这个问题经常出现,所以我将花一些时间给每个遇到这个问题的人一个更详细的答案。
首先,在您的示例中,resolved
测试通过,因为waitFor
返回一个承诺,您必须await
才能看到失败:
// ...
await waitFor(() => {
expect(get).toStrictEqual({
data1: 1,
data2: 2,
data3: 3
});
});
// ...
在这种情况下,它超时等待期望通过,因为值永远不会改变。
所以真正的问题是为什么get
不是(顺便说一句奇怪的名字)…state
在这个例子中更合适)更新时,set
被调用?
好,让我们看看这段代码:
const result = {
state: 0,
setState(newState: number) {
this.state = newState;
}
};
const { state, setState } = result;
setState(1);
expect(state).toBe(1); // fails
测试失败的原因与您的示例相同。你知道为什么吗?
result
的解构将result.state
的值锁定在一个名为state
的新变量中。调用setState
(或result.setState
)将成功更新result.state
,但没有链接到state
变量,因此值不会改变。
因此,通过const { result: { current: [get, set] } } = renderHook(...)
,您也将get
锁定为result.current
的初始值,而不是set
的数量将允许新变量更新,因为它与result.current
的连接已经丢失。
最后,我认为这是一个常见的意外,特别是在使用钩子的元组结果时(例如const [state, setState] = useState()
)。给出的常见原因是,人们不喜欢在测试中将它们称为result.current[0]
和result.current[1]
。我对此深表同情。
许多人没有意识到的另一件事是result.current
的值是你从renderHook
回调返回的任何值,所以你可以很容易地通过改变你的renderHook
调用来获得很好的命名值:
// ...
const { result } = renderHook(() => {
const [get, set] = React.useState({
data1: 0,
data2: 0,
data3: 0
})
return { get, set }
});
act(() => {
result.current.set({ data1: 1, data2: 2, data3: 3 });
});
expect(result.current.get).toStrictEqual({
data1: 1,
data2: 2,
data3: 3
});
});
// ...
无论如何,希望澄清和愉快的测试!