From: Evan You Date: Wed, 7 Apr 2021 20:19:04 +0000 (-0400) Subject: fix(watch): this.$watch should support watching keypath X-Git-Tag: v3.1.0-beta.1~66 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=870f2a7ba35245fd8c008d2ff666ea130a7e4704;p=thirdparty%2Fvuejs%2Fcore.git fix(watch): this.$watch should support watching keypath --- diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index 4a0b7a900c..0c3719e736 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -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) + }) }) diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 9c791689ed..9498ced48f 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -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 = new Set()) { if (!isObject(value) || seen.has(value)) { return value diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index e00206baa0..7b4081afec 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -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, @@ -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 {