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

无法在Vitest中测试时间相关React自定义Hook问题求助

React useInterval Hook测试时回调未执行的问题解决

问题根源

你的自定义Hook里存在一个关键错误:使用useCallback定义了更新savedCallback的逻辑,但这个函数从未被调用,导致savedCallback.current始终为undefined,当setInterval触发tick函数时,无法执行传入的回调。

原Hook中这段代码只是创建了缓存函数,没有执行逻辑:

useCallback(() => {
  savedCallback.current = callback;
}, [callback]);

修复后的useInterval Hook

将更新savedCallback的逻辑替换为useEffect,这样每当callback变化时,会自动更新ref的current值:

// useInterval.ts
import { useEffect, useRef } from "react";

function useInterval(callback: () => void, delay: number | null) {
  const savedCallback = useRef<typeof callback>();

  // 用useEffect监听callback变化,自动更新ref
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  useEffect(() => {
    function tick() {
      savedCallback.current?.();
    }
    if (delay !== null) {
      const id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
}

export default useInterval;

测试代码验证

修复Hook后,原测试逻辑可正常运行。若要验证回调调用次数,可调整断言:

// useInterval.test.ts
import { vi, expect, beforeEach, it, afterEach } from "vitest";
import { renderHook } from "@testing-library/react";
import useInterval from "./useInterval";

describe("useInterval", () => {
  beforeEach(() => {
    vi.useFakeTimers();
  });

  afterEach(() => {
    vi.useRealTimers();
  });

  test("should call the callback specified times within time range", () => {
    const mockCallback = vi.fn();
    const delay = 100;

    renderHook(() => useInterval(mockCallback, delay));

    vi.advanceTimersByTime(200);
    expect(mockCallback).toHaveBeenCalledTimes(2);
  });
});

额外说明

  • useCallback的作用是缓存函数引用,多用于传递给子组件避免重渲染,或作为其他hooks的依赖。此处需要的是自动更新ref,useEffect是更合适的选择。
  • 测试时务必在前后切换真实计时器,避免影响其他测试用例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:57:17