expect(countWE).toBe(3)
expect(countW).toBe(2)
})
+
+ const options = [
+ { name: 'only trigger once watch' },
+ {
+ deep: true,
+ name: 'only trigger once watch with deep'
+ },
+ {
+ flush: 'sync',
+ name: 'only trigger once watch with flush: sync'
+ },
+ {
+ flush: 'pre',
+ name: 'only trigger once watch with flush: pre'
+ },
+ {
+ immediate: true,
+ name: 'only trigger once watch with immediate'
+ }
+ ] as const
+ test.each(options)('$name', async option => {
+ const count = ref(0)
+ const cb = vi.fn()
+
+ watch(count, cb, { once: true, ...option })
+
+ count.value++
+ await nextTick()
+
+ expect(count.value).toBe(1)
+ expect(cb).toHaveBeenCalledTimes(1)
+
+ count.value++
+ await nextTick()
+
+ expect(count.value).toBe(2)
+ expect(cb).toHaveBeenCalledTimes(1)
+ })
})
export interface WatchOptions<Immediate = boolean> extends WatchOptionsBase {
immediate?: Immediate
deep?: boolean
+ once?: boolean
}
export type WatchStopHandle = () => void
function doWatch(
source: WatchSource | WatchSource[] | WatchEffect | object,
cb: WatchCallback | null,
- { immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
+ { immediate, deep, flush, once, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
): WatchStopHandle {
+ if (cb && once) {
+ const _cb = cb
+ cb = (...args) => {
+ _cb(...args)
+ unwatch()
+ }
+ }
+
if (__DEV__ && !cb) {
if (immediate !== undefined) {
warn(
`watch(source, callback, options?) signature.`
)
}
+ if (once !== undefined) {
+ warn(
+ `watch() "once" option is only respected when using the ` +
+ `watch(source, callback, options?) signature.`
+ )
+ }
}
const warnInvalidSource = (s: unknown) => {
const effect = new ReactiveEffect(getter, scheduler)
+ const unwatch = () => {
+ effect.stop()
+ if (instance && instance.scope) {
+ remove(instance.scope.effects!, effect)
+ }
+ }
+
if (__DEV__) {
effect.onTrack = onTrack
effect.onTrigger = onTrigger
effect.run()
}
- const unwatch = () => {
- effect.stop()
- if (instance && instance.scope) {
- remove(instance.scope.effects!, effect)
- }
- }
-
if (__SSR__ && ssrCleanup) ssrCleanup.push(unwatch)
return unwatch
}