feat(runtime-core): add `once` option to watch (#9034)
This commit is contained in:
parent
edf2572615
commit
a645e7aa51
|
@ -1205,4 +1205,42 @@ describe('api: watch', () => {
|
||||||
expect(countWE).toBe(3)
|
expect(countWE).toBe(3)
|
||||||
expect(countW).toBe(2)
|
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)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -75,6 +75,7 @@ export interface WatchOptionsBase extends DebuggerOptions {
|
||||||
export interface WatchOptions<Immediate = boolean> extends WatchOptionsBase {
|
export interface WatchOptions<Immediate = boolean> extends WatchOptionsBase {
|
||||||
immediate?: Immediate
|
immediate?: Immediate
|
||||||
deep?: boolean
|
deep?: boolean
|
||||||
|
once?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WatchStopHandle = () => void
|
export type WatchStopHandle = () => void
|
||||||
|
@ -172,8 +173,16 @@ export function watch<T = any, Immediate extends Readonly<boolean> = false>(
|
||||||
function doWatch(
|
function doWatch(
|
||||||
source: WatchSource | WatchSource[] | WatchEffect | object,
|
source: WatchSource | WatchSource[] | WatchEffect | object,
|
||||||
cb: WatchCallback | null,
|
cb: WatchCallback | null,
|
||||||
{ immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
|
{ immediate, deep, flush, once, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
|
||||||
): WatchStopHandle {
|
): WatchStopHandle {
|
||||||
|
if (cb && once) {
|
||||||
|
const _cb = cb
|
||||||
|
cb = (...args) => {
|
||||||
|
_cb(...args)
|
||||||
|
unwatch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (__DEV__ && !cb) {
|
if (__DEV__ && !cb) {
|
||||||
if (immediate !== undefined) {
|
if (immediate !== undefined) {
|
||||||
warn(
|
warn(
|
||||||
|
@ -187,6 +196,12 @@ function doWatch(
|
||||||
`watch(source, callback, options?) signature.`
|
`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 warnInvalidSource = (s: unknown) => {
|
||||||
|
@ -363,6 +378,13 @@ function doWatch(
|
||||||
|
|
||||||
const effect = new ReactiveEffect(getter, scheduler)
|
const effect = new ReactiveEffect(getter, scheduler)
|
||||||
|
|
||||||
|
const unwatch = () => {
|
||||||
|
effect.stop()
|
||||||
|
if (instance && instance.scope) {
|
||||||
|
remove(instance.scope.effects!, effect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
effect.onTrack = onTrack
|
effect.onTrack = onTrack
|
||||||
effect.onTrigger = onTrigger
|
effect.onTrigger = onTrigger
|
||||||
|
@ -384,13 +406,6 @@ function doWatch(
|
||||||
effect.run()
|
effect.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
const unwatch = () => {
|
|
||||||
effect.stop()
|
|
||||||
if (instance && instance.scope) {
|
|
||||||
remove(instance.scope.effects!, effect)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__SSR__ && ssrCleanup) ssrCleanup.push(unwatch)
|
if (__SSR__ && ssrCleanup) ssrCleanup.push(unwatch)
|
||||||
return unwatch
|
return unwatch
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue