From 2bab13011e554ea9770fe6eed86d4ce7f16aecce Mon Sep 17 00:00:00 2001 From: RicardoErii <‘1974364190@qq.com’> Date: Wed, 27 Dec 2023 00:02:47 +0800 Subject: [PATCH] fix(runtime-core): support deep: false when watch reactive --- .../runtime-core/__tests__/apiWatch.spec.ts | 32 +++++++++++++++++++ packages/runtime-core/src/apiWatch.ts | 25 +++++++++++++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index 2cb676aa8dc..5e41dcd95ba 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -156,6 +156,38 @@ describe('api: watch', () => { expect(dummy).toBe(1) }) + it('directly watching reactive object: deep: false', async () => { + const src = reactive({ + state: { + count: 0 + } + }) + let dummy + watch( + src, + ({ state }) => { + dummy = state + }, + { + deep: false + } + ) + src.state.count++ + await nextTick() + expect(dummy).toBe(undefined) + }) + + it('directly watching reactive array', async () => { + const src = reactive([0]) + let dummy + watch(src, v => { + dummy = v + }) + src.push(1) + await nextTick() + expect(dummy).toMatchObject([0, 1]) + }) + 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 6d9927d5cdc..8cfda87f9fb 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -209,8 +209,9 @@ function doWatch( getter = () => source.value forceTrigger = isShallow(source) } else if (isReactive(source)) { - getter = () => source - deep = true + deep = isShallow(source) ? false : deep ?? true + getter = deep ? () => source : () => shallowTraverse(source) + forceTrigger = true } else if (isArray(source)) { isMultiSource = true forceTrigger = source.some(s => isReactive(s) || isShallow(s)) @@ -464,3 +465,23 @@ export function traverse(value: unknown, seen?: Set) { } return value } + +export function shallowTraverse(value: unknown) { + if (!isObject(value) || (value as any)[ReactiveFlags.SKIP]) { + return value + } + if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + value[i] + } + } else if (isSet(value) || isMap(value)) { + value.forEach((v: any) => { + v + }) + } else if (isPlainObject(value)) { + for (const key in value) { + value[key] + } + } + return value +}