From bd946aa2aa09cb3d28029f65730fe3084c828cda Mon Sep 17 00:00:00 2001 From: Chizuki Date: Tue, 27 Feb 2024 12:28:44 +0800 Subject: [PATCH] feat(whenever): override once option (#3800) --- packages/shared/whenever/index.test.ts | 46 ++++++++++++++++++++++++++ packages/shared/whenever/index.ts | 28 +++++++++++++--- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/packages/shared/whenever/index.test.ts b/packages/shared/whenever/index.test.ts index 5914df20e10..c432d3d6f60 100644 --- a/packages/shared/whenever/index.test.ts +++ b/packages/shared/whenever/index.test.ts @@ -57,4 +57,50 @@ describe('whenever', () => { vm.unmount() }) + + it('once', async () => { + const vm = useSetup(() => { + const number = ref(1) + const watchCount = ref(0) + const watchValue: Ref = ref() + + whenever(number, (value) => { + watchCount.value += 1 + watchValue.value = value + expectType(value) + // @ts-expect-error value should be of type number + expectType(value) + // @ts-expect-error value should be of type number + expectType(value) + // @ts-expect-error value should be of type number + expectType(value) + }, { once: true }) + + const changeNumber = (v: number) => number.value = v + + return { + number, + watchCount, + watchValue, + changeNumber, + } + }) + + vm.changeNumber(0) + await nextTick() + expect(toValue(vm.watchCount)).toEqual(0) + expect(toValue(vm.watchValue)).toBeUndefined() + + vm.changeNumber(1) + await nextTick() + expect(toValue(vm.watchCount)).toEqual(1) + expect(toValue(vm.watchValue)).toEqual(1) + + vm.changeNumber(2) + await nextTick() + expect(toValue(vm.watchCount)).toEqual(1) + expect(toValue(vm.watchValue)).toEqual(1) + + vm.unmount() + }) }) diff --git a/packages/shared/whenever/index.ts b/packages/shared/whenever/index.ts index f8c0e9584e8..1979edc911f 100644 --- a/packages/shared/whenever/index.ts +++ b/packages/shared/whenever/index.ts @@ -1,18 +1,36 @@ import type { WatchCallback, WatchOptions, WatchSource } from 'vue-demi' -import { watch } from 'vue-demi' +import { nextTick, watch } from 'vue-demi' + +export interface WheneverOptions extends WatchOptions { + /** + * Only trigger once when the condition is met + * + * Override the `once` option in `WatchOptions` + * + * @default false + */ + once?: boolean +} /** * Shorthand for watching value to be truthy * * @see https://vueuse.org/whenever */ -export function whenever(source: WatchSource, cb: WatchCallback, options?: WatchOptions) { - return watch( +export function whenever(source: WatchSource, cb: WatchCallback, options?: WheneverOptions) { + const stop = watch( source, (v, ov, onInvalidate) => { - if (v) + if (v) { + if (options?.once) + nextTick(() => stop()) cb(v, ov, onInvalidate) + } }, - options, + { + ...options, + once: false, + } as WatchOptions, ) + return stop }