【ahooks源码】useInterval

361 阅读1分钟

官方文档对 useIntervel 的描述是:一个可以处理 setInterval 的 Hook。

在官方示例中展示的useInterval 的功能,可以概括为以下 3 条:

  1. 支持定时功能
  2. 定时器运行过程中,时间间隔可修改
  3. 定时器可以清除

首先我们先使用 hook 实现一下满足这 3 条功能要求的定时器,代码如下:

const useInterval = (fn: () => void, delay?: number) => {
  const timerCallback = fn;
  const timerRef = useRef(null);

  const clear = useCallback(() => {
    if (timerRef.current) {
      clearInterval(timerRef.current);
    }
  }, []);

  useEffect(() => {
    timerRef.current = setInterval(timerCallback, delay);
    return clear;
  }, [delay]);

  return clear;
};

export default useInterval;

使用 useRef 保存 setInterval 的 id,可以在多次渲染后持续访问这个 id。

将 clear 函数作为返回值,暴露给调用者。

现在已经支持了完整的定时器功能。

再增加不影响主逻辑的补充内容:

  1. useRef 类型定义
  2. 对于 delay 的数据校验
  3. 对入参中函数的缓存处理
  4. 标识回调函数是否立即执行的入参以及对应的逻辑判定

添加这四项之后,就完成了 ahooks 源码中的 useInterval。

useInterval 中会用到两个 ahooks 内部的工具函数, useMemoizedFn 和 isNumber,他们的用法如下:

useMemoizedFn:持久化 function 的 Hook,一般情况下,可以使用 useMemoizedFn 完全代替 useCallback。

isNumber:用于判定某个变量是否是数字类型。

useInterval 的完整实现代码如下:

// 引入 React 基本 hook
import { useCallback, useEffect, useRef } from 'react';
import useMemoizedFn from '../useMemoizedFn';
import { isNumber } from '../utils';

const useInterval = (fn: () => void, delay?: number, options: { immediate?: boolean } = {}) => {
  // 缓存入参中的函数
  const timerCallback = useMemoizedFn(fn);
  // 用 ReturnType 获取 interval 的类型
  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);

  const clear = useCallback(() => {
    if (timerRef.current) {
      clearInterval(timerRef.current);
    }
  }, []);

  useEffect(() => {
    // 对 delay 数据的校验
    if (!isNumber(delay) || delay < 0) {
      return;
    }
    // 是否立即执行一次回调函数
    if (options.immediate) {
      timerCallback();
    }
    timerRef.current = setInterval(timerCallback, delay);
    return clear;
  }, [delay, options.immediate]);

  return clear;
};

export default useInterval;