cooldown.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import { useState, useEffect, useCallback } from 'react';
  2. const getLocalStorageItem = (key: string): number | null => {
  3. if (typeof window === 'undefined') {
  4. return null;
  5. }
  6. const item = localStorage.getItem(key);
  7. return item ? parseInt(item, 10) : null;
  8. };
  9. const setLocalStorageItem = (key: string, value: number) => {
  10. if (typeof window === 'undefined') {
  11. return;
  12. }
  13. localStorage.setItem(key, value.toString());
  14. };
  15. export const useCooldown = (key: string, duration: number) => {
  16. // 在开发环境中禁用 cooldown
  17. const isDevelopment = process.env.NODE_ENV === 'development';
  18. const [cooldownEndTime, setCooldownEndTime] = useState<number | null>(() =>
  19. isDevelopment ? null : getLocalStorageItem(key)
  20. );
  21. const [remainingTime, setRemainingTime] = useState<number>(0);
  22. useEffect(() => {
  23. if (isDevelopment || !cooldownEndTime) return;
  24. const calculateRemainingTime = () => {
  25. const now = Date.now();
  26. const remaining = cooldownEndTime - now;
  27. if (remaining <= 0) {
  28. setRemainingTime(0);
  29. setCooldownEndTime(null);
  30. localStorage.removeItem(key);
  31. } else {
  32. setRemainingTime(Math.ceil(remaining / 1000));
  33. }
  34. };
  35. calculateRemainingTime();
  36. const interval = setInterval(calculateRemainingTime, 1000);
  37. return () => clearInterval(interval);
  38. }, [cooldownEndTime, key, isDevelopment]);
  39. const startCooldown = useCallback(() => {
  40. // 在开发环境中不启动 cooldown
  41. if (isDevelopment) return;
  42. const endTime = Date.now() + duration;
  43. setLocalStorageItem(key, endTime);
  44. setCooldownEndTime(endTime);
  45. }, [duration, key, isDevelopment]);
  46. const isCooldown = !isDevelopment && remainingTime > 0;
  47. return { isCooldown, startCooldown, remainingTime };
  48. };