Skip to content

Commit 069c68b

Browse files
skirtles-code9romise
authored andcommitted
fix(watch): use maximum depth for duplicates (#13434)
1 parent 023da41 commit 069c68b

File tree

2 files changed

+55
-4
lines changed

2 files changed

+55
-4
lines changed

packages/reactivity/src/watch.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,17 +291,17 @@ export function watch(
291291
export function traverse(
292292
value: unknown,
293293
depth: number = Infinity,
294-
seen?: Set<unknown>,
294+
seen?: Map<unknown, number>,
295295
): unknown {
296296
if (depth <= 0 || !isObject(value) || (value as any)[ReactiveFlags.SKIP]) {
297297
return value
298298
}
299299

300-
seen = seen || new Set()
301-
if (seen.has(value)) {
300+
seen = seen || new Map()
301+
if ((seen.get(value) || 0) >= depth) {
302302
return value
303303
}
304-
seen.add(value)
304+
seen.set(value, depth)
305305
depth--
306306
if (isRef(value)) {
307307
traverse(value.value, depth, seen)

packages/runtime-core/__tests__/apiWatch.spec.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,57 @@ describe('api: watch', () => {
17361736
expect(cb).toHaveBeenCalledTimes(4)
17371737
})
17381738

1739+
test('watching the same object at different depths', async () => {
1740+
const arr1: any[] = reactive([[[{ foo: {} }]]])
1741+
const arr2 = arr1[0]
1742+
const arr3 = arr2[0]
1743+
const obj = arr3[0]
1744+
arr1.push(arr3)
1745+
1746+
const cb1 = vi.fn()
1747+
const cb2 = vi.fn()
1748+
const cb3 = vi.fn()
1749+
const cb4 = vi.fn()
1750+
watch(arr1, cb1, { deep: 1 })
1751+
watch(arr1, cb2, { deep: 2 })
1752+
watch(arr1, cb3, { deep: 3 })
1753+
watch(arr1, cb4, { deep: 4 })
1754+
1755+
await nextTick()
1756+
expect(cb1).toHaveBeenCalledTimes(0)
1757+
expect(cb2).toHaveBeenCalledTimes(0)
1758+
expect(cb3).toHaveBeenCalledTimes(0)
1759+
expect(cb4).toHaveBeenCalledTimes(0)
1760+
1761+
obj.foo = {}
1762+
await nextTick()
1763+
expect(cb1).toHaveBeenCalledTimes(0)
1764+
expect(cb2).toHaveBeenCalledTimes(0)
1765+
expect(cb3).toHaveBeenCalledTimes(1)
1766+
expect(cb4).toHaveBeenCalledTimes(1)
1767+
1768+
obj.foo.bar = 1
1769+
await nextTick()
1770+
expect(cb1).toHaveBeenCalledTimes(0)
1771+
expect(cb2).toHaveBeenCalledTimes(0)
1772+
expect(cb3).toHaveBeenCalledTimes(1)
1773+
expect(cb4).toHaveBeenCalledTimes(2)
1774+
1775+
arr3.push(obj.foo)
1776+
await nextTick()
1777+
expect(cb1).toHaveBeenCalledTimes(0)
1778+
expect(cb2).toHaveBeenCalledTimes(1)
1779+
expect(cb3).toHaveBeenCalledTimes(2)
1780+
expect(cb4).toHaveBeenCalledTimes(3)
1781+
1782+
obj.foo.bar = 2
1783+
await nextTick()
1784+
expect(cb1).toHaveBeenCalledTimes(0)
1785+
expect(cb2).toHaveBeenCalledTimes(1)
1786+
expect(cb3).toHaveBeenCalledTimes(3)
1787+
expect(cb4).toHaveBeenCalledTimes(4)
1788+
})
1789+
17391790
test('pause / resume', async () => {
17401791
const count = ref(0)
17411792
const cb = vi.fn()

0 commit comments

Comments
 (0)