Skip to content

Commit 870f2a7

Browse files
committed
fix(watch): this.$watch should support watching keypath
1 parent 0f2d8f3 commit 870f2a7

File tree

3 files changed

+49
-13
lines changed

3 files changed

+49
-13
lines changed

packages/runtime-core/__tests__/apiWatch.spec.ts

+29
Original file line numberDiff line numberDiff line change
@@ -915,4 +915,33 @@ describe('api: watch', () => {
915915
// should not track b as dependency of Child
916916
expect(updated).toHaveBeenCalledTimes(1)
917917
})
918+
919+
test('watching keypath', async () => {
920+
const spy = jest.fn()
921+
const Comp = defineComponent({
922+
render() {},
923+
data() {
924+
return {
925+
a: {
926+
b: 1
927+
}
928+
}
929+
},
930+
watch: {
931+
'a.b': spy
932+
},
933+
created(this: any) {
934+
this.$watch('a.b', spy)
935+
},
936+
mounted(this: any) {
937+
this.a.b++
938+
}
939+
})
940+
941+
const root = nodeOps.createElement('div')
942+
createApp(Comp).mount(root)
943+
944+
await nextTick()
945+
expect(spy).toHaveBeenCalledTimes(2)
946+
})
918947
})

packages/runtime-core/src/apiWatch.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -334,11 +334,24 @@ export function instanceWatch(
334334
): WatchStopHandle {
335335
const publicThis = this.proxy as any
336336
const getter = isString(source)
337-
? () => publicThis[source]
337+
? source.includes('.')
338+
? createPathGetter(publicThis, source)
339+
: () => publicThis[source]
338340
: source.bind(publicThis)
339341
return doWatch(getter, cb.bind(publicThis), options, this)
340342
}
341343

344+
export function createPathGetter(ctx: any, path: string) {
345+
const segments = path.split('.')
346+
return () => {
347+
let cur = ctx
348+
for (let i = 0; i < segments.length && cur; i++) {
349+
cur = cur[segments[i]]
350+
}
351+
return cur
352+
}
353+
}
354+
342355
function traverse(value: unknown, seen: Set<unknown> = new Set()) {
343356
if (!isObject(value) || seen.has(value)) {
344357
return value

packages/runtime-core/src/componentOptions.ts

+6-12
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ import {
2020
isPromise
2121
} from '@vue/shared'
2222
import { computed } from './apiComputed'
23-
import { watch, WatchOptions, WatchCallback } from './apiWatch'
23+
import {
24+
watch,
25+
WatchOptions,
26+
WatchCallback,
27+
createPathGetter
28+
} from './apiWatch'
2429
import { provide, inject } from './apiInject'
2530
import {
2631
onBeforeMount,
@@ -939,17 +944,6 @@ function createWatcher(
939944
}
940945
}
941946

942-
function createPathGetter(ctx: any, path: string) {
943-
const segments = path.split('.')
944-
return () => {
945-
let cur = ctx
946-
for (let i = 0; i < segments.length && cur; i++) {
947-
cur = cur[segments[i]]
948-
}
949-
return cur
950-
}
951-
}
952-
953947
export function resolveMergedOptions(
954948
instance: ComponentInternalInstance
955949
): ComponentOptions {

0 commit comments

Comments
 (0)