useRef实现倒计时

50 阅读1分钟
import { useState, useEffect, useRef, useCallback } from 'react';

const useCountDown = (initialCount) => {
  const [count, setCount] = useState(initialCount);
  const [isRunning, setIsRunning] = useState(false);
  const timerRef = useRef(null);

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

  const start = useCallback(() => {
    if (!isRunning && count > 0) {
      setIsRunning(true);
      // 先清除可能存在的旧定时器
      clearTimer();
      // 设置新定时器
      timerRef.current = setInterval(() => {
        setCount((prevCount) => {
          if (prevCount <= 1) {
            setIsRunning(false);
            clearTimer(); // 倒计时结束,清理定时器
            return 0;
          }
          return prevCount - 1;
        });
      }, 1000);
    }
  }, [isRunning, count, clearTimer]);

  const pause = useCallback(() => {
    setIsRunning(false);
    clearTimer();
  }, [clearTimer]);

  const reset = useCallback((newCount) => {
    setIsRunning(false);
    clearTimer();
    setCount(newCount !== undefined ? newCount : initialCount);
  }, [initialCount, clearTimer]);

  // 组件卸载时,务必清理定时器防止内存泄漏
  useEffect(() => {
    return clearTimer;
  }, [clearTimer]);

  return { count, isRunning, start, pause, reset };
};

export default useCountDown;

使用

import React from 'react';
import useCountDown from './useCountDown';

const VerificationCodeButton = () => {
  const { count, isRunning, start } = useCountDown(60);

  const handleSendCode = () => {
    // 这里模拟发送验证码的请求
    console.log('发送验证码...');
    start(); // 开始倒计时
  };

  return (
    <button onClick={handleSendCode} disabled={isRunning}>
      {isRunning ? `剩余 ${count} 秒` : '获取验证码'}
    </button>
  );
};