Skip to content

Commit

Permalink
fix: support deep: false when watch reactive
Browse files Browse the repository at this point in the history
  • Loading branch information
yangmingshan committed Dec 30, 2023
1 parent 687264b commit b8617df
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 9 deletions.
109 changes: 108 additions & 1 deletion packages/wechat/__tests__/watch.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/* eslint-disable @typescript-eslint/no-unused-expressions */
import type { DebuggerEvent } from '@vue/reactivity'
import type { DebuggerEvent, ShallowRef } from '@vue/reactivity'
import {
ITERATE_KEY,
TrackOpTypes,
TriggerOpTypes,
triggerRef,
shallowReactive,
shallowRef,
} from '@vue/reactivity'
import {
Expand Down Expand Up @@ -139,6 +140,59 @@ describe('watch', () => {
expect(dummy).toBe(1)
})

it('directly watching reactive object with explicit deep: false', async () => {
const src = reactive({
state: {
count: 0,
},
})
let dummy
watch(
src,
({ state }) => {
dummy = state?.count
},
{
deep: false,
},
)

// Nested should not trigger
src.state.count++
await nextTick()
expect(dummy).toBe(undefined)

// Root level should trigger
src.state = { count: 1 }
await nextTick()
expect(dummy).toBe(1)
})

// #9916
it('directly watching shallow reactive array', async () => {
class Foo {
prop1: ShallowRef<string> = shallowRef('')
prop2 = ''
}

const obj1 = new Foo()
const obj2 = new Foo()

const collection = shallowReactive([obj1, obj2])
const cb = jest.fn()
watch(collection, cb)

collection[0].prop1.value = 'foo'
await nextTick()
// Should not trigger
expect(cb).toBeCalledTimes(0)

collection.push(new Foo())
await nextTick()
// Should trigger on array self mutation
expect(cb).toBeCalledTimes(1)
})

it('watching multiple sources', async () => {
const state = reactive({ count: 1 })
const count = ref(1)
Expand Down Expand Up @@ -770,4 +824,57 @@ describe('watch', () => {
await nextTick()
expect(dummy).toBe(1)
})

it('watching multiple sources: reactive object with explicit deep: false', async () => {
const src = reactive({
state: {
count: 0,
},
})
let dummy
watch(
[src],
([{ state }]) => {
dummy = state?.count
},
{
deep: false,
},
)

// Nested should not trigger
src.state.count++
await nextTick()
expect(dummy).toBe(undefined)

// Root level should trigger
src.state = { count: 1 }
await nextTick()
expect(dummy).toBe(1)
})

// #9916
it('watching multiple sources: shallow reactive array', async () => {
class Foo {
prop1: ShallowRef<string> = shallowRef('')
prop2 = ''
}

const obj1 = new Foo()
const obj2 = new Foo()

const collection = shallowReactive([obj1, obj2])
const cb = jest.fn()
watch([collection], cb)

collection[0].prop1.value = 'foo'
await nextTick()
// Should not trigger
expect(cb).toBeCalledTimes(0)

collection.push(new Foo())
await nextTick()
// Should trigger on array self mutation
expect(cb).toBeCalledTimes(1)
})
})
32 changes: 24 additions & 8 deletions packages/wechat/src/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,11 @@ function doWatch(
getter = () => source.value
forceTrigger = isShallow(source)
} else if (isReactive(source)) {
getter = () => source
deep = true
getter =
isShallow(source) || deep === false ?
() => traverse(source, 1)
: () => traverse(source)
forceTrigger = true
} else if (isArray(source)) {
isMultiSource = true
forceTrigger = source.some((s) => isReactive(s) || isShallow(s))
Expand All @@ -224,7 +227,7 @@ function doWatch(
}

if (isReactive(s)) {
return traverse(s)
return traverse(s, isShallow(s) || deep === false ? 1 : undefined)
}

if (isFunction(s)) {
Expand Down Expand Up @@ -359,11 +362,24 @@ function doWatch(
return unwatch
}

function traverse(value: unknown, seen?: Set<unknown>): unknown {
function traverse(
value: unknown,
depth?: number,
currentDepth = 0,
seen?: Set<unknown>,
): unknown {
if (!isObject(value) || (value as any)[ReactiveFlags.SKIP]) {
return value
}

if (depth && depth > 0) {
if (currentDepth >= depth) {
return value
}

currentDepth++
}

seen = seen || new Set()
if (seen.has(value)) {
return value
Expand All @@ -372,19 +388,19 @@ function traverse(value: unknown, seen?: Set<unknown>): unknown {
seen.add(value)
/* istanbul ignore else */
if (isRef(value)) {
traverse(value.value, seen)
traverse(value.value, depth, currentDepth, seen)
} else if (isArray(value)) {
for (let i = 0; i < value.length; i++) {
traverse(value[i], seen)
traverse(value[i], depth, currentDepth, seen)
}
} else if (isSet(value) || isMap(value)) {
value.forEach((v: any) => {
traverse(v, seen)
traverse(v, depth, currentDepth, seen)
})
} else if (isPlainObject(value)) {
// eslint-disable-next-line guard-for-in
for (const key in value) {
traverse(value[key], seen)
traverse(value[key], depth, currentDepth, seen)
}
}

Expand Down

0 comments on commit b8617df

Please sign in to comment.