Memulai
Siklus Hidup
Peramban
Pengembangan
Paket Luar
useInterval
Menjalankan sesuatu berulang kali, dengan jeda yang boleh berubah.
0s
Bedanya dari setInterval telanjang ada tiga, dan ketiganya sering jadi sumber cacat: timernya ikut mati bersama scope, jedanya bisa diganti tanpa memasang ulang, dan null menghentikannya tanpa perlu cabang if di pemanggilnya.
delay berupa null atau angka negatif berarti berhenti. Itu yang membuat pola "jalan hanya saat tab terlihat" jadi satu baris:
ts
const terlihat = useDocumentVisibility()
useInterval(muatUlang, () => (terlihat.value === 'visible' ? 5000 : null))Pemasangan
npx shadcn-vue@latest add @kliping/use-interval Perlu @kliping terdaftar di components.json project Anda. Lihat cara menyiapkannya.
Ikut terpasang sendiri: is-browser.
Salin dulu is-browser — masing-masing memuat sumbernya di halamannya sendiri — lalu tempel berkas ini.
ts
import { getCurrentScope, onScopeDispose, readonly, ref, toValue, watch } from 'vue'
import type { MaybeRefOrGetter } from 'vue'
import { isBrowser } from '@/lib/is-browser'
export interface UseIntervalOptions {
/** Jalankan sekali seketika, sebelum jeda pertama dihitung. */
immediate?: boolean
}
export function useInterval(
fn: () => void,
delay: MaybeRefOrGetter<number | null> = 1000,
options: UseIntervalOptions = {},
) {
const { immediate = false } = options
const berjalan = ref(false)
let timer: ReturnType<typeof setInterval> | undefined
const pause = () => {
if (timer !== undefined) {
clearInterval(timer)
timer = undefined
}
berjalan.value = false
}
const mulai = (jeda: number) => {
pause()
// Di server tidak ada yang menonton, dan timer yang dibuat di sana membuat
// event loop Node tidak pernah kosong — `vitepress build` menggantung
// selamanya tanpa satu pun pesan galat. Ditemukan persis begitu.
if (!isBrowser)
return
if (immediate)
fn()
timer = setInterval(fn, jeda)
berjalan.value = true
}
const resume = () => {
const jeda = toValue(delay)
if (typeof jeda === 'number' && jeda >= 0)
mulai(jeda)
}
watch(
() => toValue(delay),
(jeda) => {
if (typeof jeda !== 'number' || jeda < 0) {
pause()
return
}
mulai(jeda)
},
{ immediate: true },
)
if (getCurrentScope())
onScopeDispose(pause)
return { isActive: readonly(berjalan), pause, resume }
}API
ts
export interface UseIntervalOptions {
/** Jalankan sekali seketika, sebelum jeda pertama dihitung. */
immediate?: boolean
}
export function useInterval(
fn: () => void,
delay: MaybeRefOrGetter<number | null> = 1000,
options: UseIntervalOptions = {},
)