在自定义钩子中测试状态更新时为什么需要 act() ?

问题描述 投票:0回答:1

StackBlitz 示例 - 打开新终端并

npm t

我阅读了act

上的文档和这个解释,我明白它只是确保在任何断言之前状态一直更新。然后他们说:

所有渲染和触发的事件都包含在

act
中,所以你并不真正需要这个。

所以如果我有一个简单的

useCounter
钩子:

function useCounter(args?: { init: number; by: number }) {
  const init = args?.init || 0;
  const by = args?.by || 1;
  const [count, setCount] = useState(init);

  const increment = () => setCount((p) => p + by);
  const decrement = () => setCount((p) => p - by);

  return { count, increment, decrement };
}

并隔离测试它

test('state update in isolation', () => { const { result } = renderHook((props) => useCounter(props), { initialProps: { init: 5, by: 3 }, }); expect(result.current.count).toBe(5); // act(() => result.current.increment()); // use this and test passes result.current.decrement(); // use this and test fails: expected 8 and get 5 expect(result.current.count).toBe(8); });
但是只有当我将 

increment

 包裹在 
act
 中时,我的测试才能通过。我以为它应该是自动包装的?

所以我不确定应该如何使用

act

,什么时候暗示,什么时候不暗示?

我同时使用 act

renderHook
 中的 
@testing-library/react
,如果这有区别的话。

react-hooks react-testing-library
1个回答
0
投票
当您测试像

useCounter

这样的钩子时,如果您直接更改其状态(例如调用
result.current.decrement()
),则需要将该操作包装在
act()
中。尽管 
renderHook()
 已经处理了大部分事情,但钩子内的状态更新需要 
act()
 来确保您的测试行为一致。因此,在测试中直接修改状态时,请始终使用 
act()

您可以阅读这篇

中篇文章了解详细信息。

© www.soinside.com 2019 - 2024. All rights reserved.