// should not track b as dependency of Child
expect(updated).toHaveBeenCalledTimes(1)
})
+
+ test('watching keypath', async () => {
+ const spy = jest.fn()
+ const Comp = defineComponent({
+ render() {},
+ data() {
+ return {
+ a: {
+ b: 1
+ }
+ }
+ },
+ watch: {
+ 'a.b': spy
+ },
+ created(this: any) {
+ this.$watch('a.b', spy)
+ },
+ mounted(this: any) {
+ this.a.b++
+ }
+ })
+
+ const root = nodeOps.createElement('div')
+ createApp(Comp).mount(root)
+
+ await nextTick()
+ expect(spy).toHaveBeenCalledTimes(2)
+ })
})
): WatchStopHandle {
const publicThis = this.proxy as any
const getter = isString(source)
- ? () => publicThis[source]
+ ? source.includes('.')
+ ? createPathGetter(publicThis, source)
+ : () => publicThis[source]
: source.bind(publicThis)
return doWatch(getter, cb.bind(publicThis), options, this)
}
+export function createPathGetter(ctx: any, path: string) {
+ const segments = path.split('.')
+ return () => {
+ let cur = ctx
+ for (let i = 0; i < segments.length && cur; i++) {
+ cur = cur[segments[i]]
+ }
+ return cur
+ }
+}
+
function traverse(value: unknown, seen: Set<unknown> = new Set()) {
if (!isObject(value) || seen.has(value)) {
return value
isPromise
} from '@vue/shared'
import { computed } from './apiComputed'
-import { watch, WatchOptions, WatchCallback } from './apiWatch'
+import {
+ watch,
+ WatchOptions,
+ WatchCallback,
+ createPathGetter
+} from './apiWatch'
import { provide, inject } from './apiInject'
import {
onBeforeMount,
}
}
-function createPathGetter(ctx: any, path: string) {
- const segments = path.split('.')
- return () => {
- let cur = ctx
- for (let i = 0; i < segments.length && cur; i++) {
- cur = cur[segments[i]]
- }
- return cur
- }
-}
-
export function resolveMergedOptions(
instance: ComponentInternalInstance
): ComponentOptions {