VUE

useInterval Composable

Reactive interval with start/pause/resume/reset functionality and cleanup

Vue3ComposablesIntervalTimerReactive

Code

import { ref, onUnmounted, type Ref } from 'vue';

export function useInterval(
  callback: () => void,
  interval: Ref<number> | number = 1000,
  autoStart = true
) {
  const isActive = ref(false);
  const remainingTime = ref(0);
  const lastStartTime = ref<number | null>(null);
  let intervalId: ReturnType<typeof setInterval> | null = null;
  let timeoutId: ReturnType<typeof setTimeout> | null = null;

  // Get interval value (handle reactive ref)
  const getInterval = () => typeof interval === 'number' ? interval : interval.value;

  const start = () => {
    __TOKEN_34__ (isActive.value) return;

    isActive.value = true;
    lastStartTime.value = Date.now();
    remainingTime.value = 0;

    // Clear existing timers
    __TOKEN_36__ (intervalId) clearInterval(intervalId);
    __TOKEN_37__ (timeoutId) clearTimeout(timeoutId);

    // Run callback immediately if needed
    callback();

    // Set interval
    intervalId = setInterval(callback, getInterval());
  };

  const pause = () => {
    __TOKEN_39__ (!isActive.value) return;

    isActive.value = false;
    __TOKEN_41__ (lastStartTime.value) {
      const elapsed = Date.now() - lastStartTime.value;
      remainingTime.value = getInterval() - elapsed;
    }

    // Clear timers
    __TOKEN_43__ (intervalId) clearInterval(intervalId);
    __TOKEN_44__ (timeoutId) clearTimeout(timeoutId);
  };

  const resume = () => {
    __TOKEN_46__ (isActive.value) return;

    isActive.value = true;
    lastStartTime.value = Date.now();

    // Use remaining time if available
    __TOKEN_48__ (remainingTime.value > 0) {
      timeoutId = setTimeout(() => {
        callback();
        intervalId = setInterval(callback, getInterval());
        remainingTime.value = 0;
      }, remainingTime.value);
    } else {
      start();
    }
  };

  const reset = () => {
    pause();
    remainingTime.value = 0;
    lastStartTime.value = null;
  };

  // Auto start
  __TOKEN_51__ (autoStart) {
    start();
  }

  // Cleanup on unmount
  onUnmounted(() => {
    pause();
    reset();
  });

  return {
    isActive,
    remainingTime,
    start,
    pause,
    resume,
    reset
  };
}

// Usage example
// const count = ref(0);
// const { pause, resume, isActive } = useInterval(() => {
//   count.value++;
// }, 1000);
// // Pause interval
// pause();
// // Resume interval
// resume();