Skip to content

Commit

Permalink
fix(watch): this.$watch should support watching keypath
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Apr 7, 2021
1 parent 0f2d8f3 commit 870f2a7
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 13 deletions.
29 changes: 29 additions & 0 deletions packages/runtime-core/__tests__/apiWatch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -915,4 +915,33 @@ describe('api: watch', () => {
// 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)
})
})
15 changes: 14 additions & 1 deletion packages/runtime-core/src/apiWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,11 +334,24 @@ export function instanceWatch(
): 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
Expand Down
18 changes: 6 additions & 12 deletions packages/runtime-core/src/componentOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ import {
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,
Expand Down Expand Up @@ -939,17 +944,6 @@ function createWatcher(
}
}

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 {
Expand Down

0 comments on commit 870f2a7

Please sign in to comment.