perf(watch): avoid double traverse for reactive source

This commit is contained in:
Evan You 2023-12-31 17:29:58 +08:00
parent 8f85b6da44
commit 24d77c25ce
2 changed files with 26 additions and 6 deletions

View File

@ -211,6 +211,24 @@ describe('api: watch', () => {
expect(cb).toBeCalledTimes(1) 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 () => { it('watching multiple sources', async () => {
const state = reactive({ count: 1 }) const state = reactive({ count: 1 })
const count = ref(1) const count = ref(1)

View File

@ -222,7 +222,12 @@ function doWatch(
const instance = const instance =
getCurrentScope() === currentInstance?.scope ? currentInstance : null 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 getter: () => any
let forceTrigger = false let forceTrigger = false
let isMultiSource = false let isMultiSource = false
@ -231,10 +236,7 @@ function doWatch(
getter = () => source.value getter = () => source.value
forceTrigger = isShallow(source) forceTrigger = isShallow(source)
} else if (isReactive(source)) { } else if (isReactive(source)) {
getter = getter = () => reactiveGetter(source)
isShallow(source) || deep === false
? () => traverse(source, 1)
: () => traverse(source)
forceTrigger = true forceTrigger = true
} else if (isArray(source)) { } else if (isArray(source)) {
isMultiSource = true isMultiSource = true
@ -244,7 +246,7 @@ function doWatch(
if (isRef(s)) { if (isRef(s)) {
return s.value return s.value
} else if (isReactive(s)) { } else if (isReactive(s)) {
return traverse(s, isShallow(s) || deep === false ? 1 : undefined) return reactiveGetter(s)
} else if (isFunction(s)) { } else if (isFunction(s)) {
return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER) return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
} else { } else {