|
@@ -0,0 +1,65 @@
|
|
|
+import { useLatest } from "ahooks";
|
|
|
+import { useEffect, useState } from "react";
|
|
|
+
|
|
|
+export interface Options {
|
|
|
+ // 剩余时间(毫秒)
|
|
|
+ leftTime?: number;
|
|
|
+ // 计时器间隔(毫秒)
|
|
|
+ interval?: number;
|
|
|
+ // 倒计时结束回调
|
|
|
+ onEnd?: () => void;
|
|
|
+}
|
|
|
+
|
|
|
+export interface FormattedRes {
|
|
|
+ days: number;
|
|
|
+ hours: number;
|
|
|
+ minutes: number;
|
|
|
+ seconds: number;
|
|
|
+ milliseconds: number;
|
|
|
+}
|
|
|
+
|
|
|
+const parseMs = (milliseconds: number): FormattedRes => {
|
|
|
+ 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,
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description 根据服务器返回秒数完成倒计时, 不使用本地时间
|
|
|
+ */
|
|
|
+const useCountdown = (options: Options = {}) => {
|
|
|
+ const { leftTime = 0, interval = 1000, onEnd } = options;
|
|
|
+ const [timeLeft, setTimeLeft] = useState(leftTime);
|
|
|
+ const onEndRef = useLatest(onEnd);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ setTimeLeft(leftTime);
|
|
|
+
|
|
|
+ if (leftTime <= 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const timer = setInterval(() => {
|
|
|
+ setTimeLeft((prev) => {
|
|
|
+ const nextTimeLeft = Math.max(0, prev - interval);
|
|
|
+ if (nextTimeLeft === 0) {
|
|
|
+ clearInterval(timer);
|
|
|
+ onEndRef.current?.();
|
|
|
+ }
|
|
|
+ return nextTimeLeft;
|
|
|
+ });
|
|
|
+ }, interval);
|
|
|
+
|
|
|
+ return () => clearInterval(timer);
|
|
|
+ }, [leftTime, interval]);
|
|
|
+
|
|
|
+ const formattedRes = parseMs(timeLeft);
|
|
|
+
|
|
|
+ return [timeLeft, formattedRes] as const;
|
|
|
+};
|
|
|
+
|
|
|
+export default useCountdown;
|