← All tasksReact · Senior

useInterval hook

Write a useInterval(callback, delay) hook that calls callback every delay milliseconds while the component is mounted.

Each call must use the latest version of callback with current props and state, but a new function on every render must not restart the interval. delay = null pauses the interval. After unmounting there are no more calls.

Tests (5)

  1. const f = fn();
    renderHook(() => useInterval(f, 30));
    await wait(110);
    expect(f.calls.length >= 2 && f.calls.length <= 4).toBe(true);
  2. const log = [];
    const { rerender } = renderHook(({ n }) => useInterval(() => log.push(n), 30), { initialProps: { n: 1 } });
    await wait(45);
    rerender({ n: 2 });
    await wait(50);
    expect(log[0]).toBe(1);
    expect(log[log.length - 1]).toBe(2);
  3. const f = fn();
    const { rerender } = renderHook(() => useInterval(() => f(), 40));
    for (let i = 0; i < 6; i++) {
      await wait(15);
      rerender();
    }
    expect(f.calls.length >= 1).toBe(true);
  4. const f = fn();
    renderHook(() => useInterval(f, null));
    await wait(60);
    expect(f).toHaveBeenCalledTimes(0);
  5. const f = fn();
    const { unmount } = renderHook(() => useInterval(f, 20));
    unmount();
    await wait(60);
    expect(f).toHaveBeenCalledTimes(0);