useCountDown 时分秒 倒计时

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

const parseMs = (milliseconds) => {
    const hour = Math.floor(milliseconds / 3600000) % 24
    const minute = Math.floor(milliseconds / 60000) % 60
    const second = Math.floor(milliseconds / 1000) % 60
    return {
        days: Math.floor(milliseconds / 86400000),
        hours: hour < 10 ? '0' + hour : hour,
        minutes: minute < 10 ? '0' + minute : minute,
        seconds: second < 10 ? '0' + second : second,
    }
}

const useCountDown = (endTimeStamp) => {
    const timer = useRef(null)
    const [remainingTime, setRemainingTime] = useState(0) // 修复:正确的初始状态

    // 修复:使用useCallback避免不必要的重新创建
    const calcTimeDiff = useCallback(() => {
        const currentTime = Date.now() // 修复:使用Date.now()更简洁
        const diff = Math.max(0, (endTimeStamp || 0) - currentTime) // 修复:确保不为负数
        
        if (diff <= 0) {
            if (timer.current) {
                clearInterval(timer.current)
                timer.current = null
            }
        }
        
        setRemainingTime(diff)
        return diff > 0
    }, [endTimeStamp])

    useEffect(() => {
        // 修复:先清理之前的定时器
        if (timer.current) {
            clearInterval(timer.current)
        }

        // 立即计算一次
        const isActive = calcTimeDiff()
        
        // 只有在倒计时还在进行时才创建定时器
        if (isActive) {
            timer.current = setInterval(() => {
                const stillActive = calcTimeDiff()
                if (!stillActive && timer.current) {
                    clearInterval(timer.current)
                    timer.current = null
                }
            }, 1000)
        }

        // 清理函数
        return () => {
            if (timer.current) {
                clearInterval(timer.current)
                timer.current = null
            }
        }
    }, [calcTimeDiff])

    const { days, hours, minutes, seconds } = parseMs(remainingTime)
    return { 
        days, 
        hours, 
        minutes, 
        seconds,
        isFinished: remainingTime <= 0 // 额外返回是否结束的状态
    }
}

export default useCountDown