From 24d77c25ce5d5356adb5367beef1d23e6e340b35 Mon Sep 17 00:00:00 2001 From: Evan You Date: Sun, 31 Dec 2023 17:29:58 +0800 Subject: [PATCH] perf(watch): avoid double traverse for reactive source --- .../runtime-core/__tests__/apiWatch.spec.ts | 18 ++++++++++++++++++ packages/runtime-core/src/apiWatch.ts | 14 ++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index b25635e664e..c82b06c1a8b 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -211,6 +211,24 @@ describe('api: watch', () => { expect(cb).toBeCalledTimes(1) }) + it('should still respect deep: true on shallowReactive source', async () => { + const obj = reactive({ a: 1 }) + const arr = shallowReactive([obj]) + + let dummy + watch( + arr, + () => { + dummy = arr[0].a + }, + { deep: true }, + ) + + obj.a++ + await nextTick() + expect(dummy).toBe(2) + }) + it('watching multiple sources', async () => { const state = reactive({ count: 1 }) const count = ref(1) diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 0c13e72988f..d840864454f 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -222,7 +222,12 @@ function doWatch( const instance = getCurrentScope() === currentInstance?.scope ? currentInstance : null - // const instance = currentInstance + const reactiveGetter = (source: object) => + deep === true + ? source // traverse will happen in wrapped getter below + : // for shallow or deep: false, only traverse root-level properties + traverse(source, isShallow(source) || deep === false ? 1 : undefined) + let getter: () => any let forceTrigger = false let isMultiSource = false @@ -231,10 +236,7 @@ function doWatch( getter = () => source.value forceTrigger = isShallow(source) } else if (isReactive(source)) { - getter = - isShallow(source) || deep === false - ? () => traverse(source, 1) - : () => traverse(source) + getter = () => reactiveGetter(source) forceTrigger = true } else if (isArray(source)) { isMultiSource = true @@ -244,7 +246,7 @@ function doWatch( if (isRef(s)) { return s.value } else if (isReactive(s)) { - return traverse(s, isShallow(s) || deep === false ? 1 : undefined) + return reactiveGetter(s) } else if (isFunction(s)) { return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER) } else {