react简单定时器纠偏

139 阅读1分钟
export const useCountDown = (countDownTimeStamp: number) => {
    // 倒计时时间
    const [second, setSecond] = useState(0);

    const interval = 1000;

    // 计时器执行次数
    const countRef = useRef(0);
    // 记录定时器引用
    const timerRef = useRef<ReturnType<typeof setTimeout> | null>(0);
    // 任务开始时间
    const startTimeRef = useRef(0);

    const countTask = useCallback(() => {
        countRef.current += 1;
        // 计算时间偏差
        const offset = +new Date() - (startTimeRef.current + interval * countRef.current);
        let nextTime = interval - offset;
        nextTime <= 0 && (nextTime = 0);

        setSecond(pre => {
            const resuide = pre - 1;
            if (resuide <= 0) {
                timerRef.current && clearTimeout(timerRef.current);
                return 0;
            } else {
                setTimeout(countTask, nextTime);
                return resuide;
            }
        });
    }, []);

    useEffect(() => {
        startTimeRef.current = new Date().getTime();
        setSecond(countDownTimeStamp);
        const timer = timerRef.current;
        setTimeout(countTask, interval);
        return () => {
            if (timer) {
                clearTimeout(timer);
                timerRef.current = null;
            }
        };
    }, [countDownTimeStamp, countTask]);

    return { second };
};