ahooks
Version:
react hooks library
53 lines (52 loc) • 1.93 kB
JavaScript
import dayjs from 'dayjs';
import { useEffect, useMemo, useState } from 'react';
import useLatest from '../useLatest';
import { isNumber } from '../utils';
const calcLeft = (target) => {
if (!target) {
return 0;
}
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
const left = dayjs(target).valueOf() - Date.now();
return left < 0 ? 0 : left;
};
const parseMs = (milliseconds) => {
return {
days: Math.floor(milliseconds / 86400000),
hours: Math.floor(milliseconds / 3600000) % 24,
minutes: Math.floor(milliseconds / 60000) % 60,
seconds: Math.floor(milliseconds / 1000) % 60,
milliseconds: Math.floor(milliseconds) % 1000,
};
};
const useCountdown = (options = {}) => {
const { leftTime, targetDate, interval = 1000, onEnd } = options || {};
const memoLeftTime = useMemo(() => {
return isNumber(leftTime) && leftTime > 0 ? Date.now() + leftTime : undefined;
}, [leftTime]);
const target = 'leftTime' in options ? memoLeftTime : targetDate;
const [timeLeft, setTimeLeft] = useState(() => calcLeft(target));
const onEndRef = useLatest(onEnd);
useEffect(() => {
if (!target) {
// for stop
setTimeLeft(0);
return;
}
// 立即执行一次
setTimeLeft(calcLeft(target));
const timer = setInterval(() => {
var _a;
const targetLeft = calcLeft(target);
setTimeLeft(targetLeft);
if (targetLeft === 0) {
clearInterval(timer);
(_a = onEndRef.current) === null || _a === void 0 ? void 0 : _a.call(onEndRef);
}
}, interval);
return () => clearInterval(timer);
}, [target, interval]);
const formattedRes = useMemo(() => parseMs(timeLeft), [timeLeft]);
return [timeLeft, formattedRes];
};
export default useCountdown;