自定义 Hook之 setTimeout 延迟调用

771 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

通过自定义 Hook,可以将组件逻辑提取到可重用的函数中。自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook。

useRef

const refContainer = useRef(initialValue);

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。

TypeScript

TypeScript是JavaScript的超集,具有可选的类型并可以编译为纯JavaScript。从技术上讲TypeScript就是具有静态类型的 JavaScript 。

图片.png

动态类型的自由特性经常会导致错误,这些错误不仅会降低程序员的工作效率,而且还会由于增加新代码行的成本增加而使开发陷入停顿。

因此,JavaScript无法合并类型以及编译时缺乏错误检查,使它不适合作为企业和大型代码库中服务器端代码。


使用 setTimeout 和 clearTimeout 实现功能。

该 hook 返回两个函数 startTimer(启动计时器,入参为延时到期的回调函数) 和 clearTimer(清除计时器)。入参为延迟的毫秒数。

import { useEffect, useState, useRef, useCallback } from 'react';

interface IUseTimeOutReturn {
  /** 启动计时器,入参为延时到期的回调函数 */
  startTimer: (callback: Function) => void;
  /** 清楚计时器 */
  clearTimer: Function;
}

/**
 * 延迟调用
 * @param ms 延迟的毫秒数
 * @returns 返回开始定时器和清楚定时器的方法
 */
const useTimeOut = (ms: number): IUseTimeOutReturn => {
  const [leftMs, setLeftMs] = useState(ms);
  let timerRef = useRef<any>(null);

  const clearTimer = useCallback(() => {
    timerRef.current && clearTimeout(timerRef.current);
    timerRef.current = null;
  }, []);

  useEffect(() => {
    if (ms !== leftMs) {
      setLeftMs(ms);
    }
  }, [leftMs, ms]);

  const startTimer = useCallback(
    (callback: Function) => {
      clearTimer();
      timerRef.current = setTimeout(() => {
        callback();
        clearTimer();
      }, leftMs);
    },
    [clearTimer, leftMs]
  );

  return {
    startTimer,
    clearTimer
  };
};

export default useTimeOut;

使用的方法

import useTimeOut from './hook/useTimeOut';

function App() {
  const { startTimer, clearTimer } = useTimeOut(10000);

  const handleClick = () => {
    startTimer(() => {
      console.log('延迟调用')
    });
  };

  return (
    <div className="App">
      <button onClick={handleClick}>button</button>
    </div>
  );
}

export default App;