You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-testing-library多次点击按钮仅渲染1张图片而非新增多张如何解决

问题原因
  • 核心是React异步状态更新的闭包陷阱:你定义的getDogPhoto异步函数会捕获函数创建时的dogPhotos状态值,连续快速点击5次时,5次调用捕获的都是初始的空数组[]
  • 每次执行setDogPhotos时,都是基于空数组拼接新图片地址,5次更新的结果都是长度为1的数组,最终只会渲染最后一次更新的图片
  • 测试中未等待异步请求完成就连续触发点击,进一步放大了这个问题,但核心原因是状态更新的写法缺陷。
修复方案

修改getDogPhoto中的状态更新逻辑,使用函数式更新获取最新的状态值,避免依赖闭包捕获的旧状态:

export const DogGallery = () => {
  const [dogPhotos, setDogPhotos] = useState([]);
  const getDogPhoto = async () => {
    const newPhoto = await fetch(
      "https://dog.ceo/api/breeds/image/random"
    ).then((res) => res.json());
    // 改用函数式更新,参数prevPhotos是当前最新的状态值,不受闭包影响
    setDogPhotos(prevPhotos => [...prevPhotos, newPhoto.message]);
  };
  return (
    <>
      <p>Dog gallery</p>
      <Button handleClick={getDogPhoto} />
      {dogPhotos.length > 0 &&
        dogPhotos.map((photo, i) => (
          <DogPhoto source={photo} key={i} number={i} />
        ))}
    </>
  );
};
测试优化建议

为了让测试更稳定,建议做以下修改:

  • Mock全局fetch方法,返回固定的测试图片地址,避免依赖外部接口造成测试波动
  • 可以选择每次点击后等待对应图片渲染完成,再触发下一次点击,也可以直接用waitFor等待5张图片全部渲染:
it("should render 5 images", async () => {
  render(<DogGallery />);
  // 连续触发5次点击
  for(let i=0; i<5; i++){
    fireEvent.click(screen.getByText("click!"));
  }
  // 等待最多3秒直到渲染出5张图片
  const elements = await waitFor(
    () => screen.findAllByRole("image"),
    { timeout: 3000 }
  );
  expect(elements.length).toBe(5);
});

内容的提问来源于stack exchange,提问作者crevulus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 05:24:00