From 014fa6654eae647aff33af7c21cd65ec759f6897 Mon Sep 17 00:00:00 2001 From: sh7dm Date: Sun, 13 Oct 2019 13:29:43 +0300 Subject: [PATCH] feat(instanceWatch): watch nested value by path --- .../__tests__/componentProxy.spec.ts | 37 ++++++++++++++++++- packages/runtime-core/src/apiWatch.ts | 22 ++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/__tests__/componentProxy.spec.ts b/packages/runtime-core/__tests__/componentProxy.spec.ts index aa951c3a609..4b2b5d66b0f 100644 --- a/packages/runtime-core/__tests__/componentProxy.spec.ts +++ b/packages/runtime-core/__tests__/componentProxy.spec.ts @@ -2,7 +2,8 @@ import { createApp, getCurrentInstance, nodeOps, - mockWarn + mockWarn, + nextTick } from '@vue/runtime-test' import { ComponentInternalInstance } from '../src/component' @@ -129,4 +130,38 @@ describe('component: proxy', () => { expect(instanceProxy.foo).toBe(1) expect(instance!.user.foo).toBe(1) }) + + it('watch', async () => { + const foobar = jest.fn() + + const app = createApp() + let instanceProxy: any + const Comp = { + data() { + return { + foo: { + bar: 1, + baz: 2 + } + } + }, + mounted() { + instanceProxy = this + }, + render() { + return null + } + } + app.mount(Comp, nodeOps.createElement('div')) + instanceProxy.$watch('foo.bar', foobar) + + instanceProxy.foo.bar++ + await nextTick() + expect(foobar).toHaveBeenCalledTimes(1) + expect(foobar.mock.calls[0][0]).toBe(2) + + instanceProxy.foo.baz++ + await nextTick() + expect(foobar).toHaveBeenCalledTimes(1) + }) }) diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 927db333212..8eb1536da5a 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -203,6 +203,24 @@ function doWatch( } } +function getValueByPath( + object: any, + path: string, + fallback?: T +): T | undefined { + const pathSegments = path.split('.') + + for (let i = 0; i < pathSegments.length; i++) { + if (object[pathSegments[i]]) { + object = object[pathSegments[i]] + } else { + return fallback + } + } + + return object +} + // this.$watch export function instanceWatch( this: ComponentInternalInstance, @@ -211,7 +229,9 @@ export function instanceWatch( options?: WatchOptions ): StopHandle { const ctx = this.renderProxy! - const getter = isString(source) ? () => ctx[source] : source.bind(ctx) + const getter = isString(source) + ? () => getValueByPath(ctx, source) + : source.bind(ctx) const stop = watch(getter, cb.bind(ctx), options) onBeforeUnmount(stop, this) return stop