]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(watch): this.$watch should support watching keypath
authorEvan You <yyx990803@gmail.com>
Wed, 7 Apr 2021 20:19:04 +0000 (16:19 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 7 Apr 2021 20:19:04 +0000 (16:19 -0400)
packages/runtime-core/__tests__/apiWatch.spec.ts
packages/runtime-core/src/apiWatch.ts
packages/runtime-core/src/componentOptions.ts

index 4a0b7a900c0ae7c2ac8e58c73d6a406cab372c06..0c3719e7364654cfab7b88c34eba5730b6afcd1b 100644 (file)
@@ -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)
+  })
 })
index 9c791689ed610573f42416c81cf89855b3906e99..9498ced48fbb964fee7b835e6070a44db856a220 100644 (file)
@@ -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
index e00206baa003f7d230b029fd071bf1abf1c801b7..7b4081afecc9e7d944f9043b13e3596b7c63636e 100644 (file)
@@ -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 {