Skip to content

Commit

Permalink
feat(runtime-core): add once option to watch (#9034)
Browse files Browse the repository at this point in the history
  • Loading branch information
Alfred-Skyblue authored and sxzz committed Oct 27, 2023
1 parent edf2572 commit a645e7a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
38 changes: 38 additions & 0 deletions packages/runtime-core/__tests__/apiWatch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1205,4 +1205,42 @@ describe('api: watch', () => {
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)
})
})
31 changes: 23 additions & 8 deletions packages/runtime-core/src/apiWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export interface WatchOptionsBase extends DebuggerOptions {
export interface WatchOptions<Immediate = boolean> extends WatchOptionsBase {
immediate?: Immediate
deep?: boolean
once?: boolean
}

export type WatchStopHandle = () => void
Expand Down Expand Up @@ -172,8 +173,16 @@ export function watch<T = any, Immediate extends Readonly<boolean> = false>(
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(
Expand All @@ -187,6 +196,12 @@ function doWatch(
`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) => {
Expand Down Expand Up @@ -363,6 +378,13 @@ function doWatch(

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
Expand All @@ -384,13 +406,6 @@ function doWatch(
effect.run()
}

const unwatch = () => {
effect.stop()
if (instance && instance.scope) {
remove(instance.scope.effects!, effect)
}
}

if (__SSR__ && ssrCleanup) ssrCleanup.push(unwatch)
return unwatch
}
Expand Down

0 comments on commit a645e7a

Please sign in to comment.