diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index 5f4dd323b16..a25e7c41989 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -290,9 +290,12 @@ describe('api: watch', () => { }) it('deep', async () => { + const countSymbol = Symbol('countSymbol') + const state = reactive({ nested: { - count: ref(0) + count: ref(0), + [countSymbol]: ref(0) }, array: [1, 2, 3], map: new Map([['a', 1], ['b', 2]]), @@ -305,6 +308,7 @@ describe('api: watch', () => { state => { dummy = [ state.nested.count, + state.nested[countSymbol], state.array[0], state.map.get('a'), state.set.has(1) @@ -314,26 +318,30 @@ describe('api: watch', () => { ) await nextTick() - expect(dummy).toEqual([0, 1, 1, true]) + expect(dummy).toEqual([0, 0, 1, 1, true]) state.nested.count++ await nextTick() - expect(dummy).toEqual([1, 1, 1, true]) + expect(dummy).toEqual([1, 0, 1, 1, true]) + + state.nested[countSymbol]++ + await nextTick() + expect(dummy).toEqual([1, 1, 1, 1, true]) // nested array mutation state.array[0] = 2 await nextTick() - expect(dummy).toEqual([1, 2, 1, true]) + expect(dummy).toEqual([1, 1, 2, 1, true]) // nested map mutation state.map.set('a', 2) await nextTick() - expect(dummy).toEqual([1, 2, 2, true]) + expect(dummy).toEqual([1, 1, 2, 2, true]) // nested set mutation state.set.delete(1) await nextTick() - expect(dummy).toEqual([1, 2, 2, false]) + expect(dummy).toEqual([1, 1, 2, 2, false]) }) it('lazy', async () => { diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 4a8248aa0a3..7c2a3da6380 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -234,17 +234,26 @@ function traverse(value: unknown, seen: Set = new Set()) { traverse(value[i], seen) } } else if (value instanceof Map) { - value.forEach((v, key) => { - // to register mutation dep for existing keys - traverse(value.get(key), seen) - }) + const keys = [...value.keys()] + + for (let i = 0; i < keys.length; i++) { + traverse(value.get(keys[i]), seen) + } } else if (value instanceof Set) { - value.forEach(v => { - traverse(v, seen) - }) + const values = [...value.values()] + + for (let i = 0; i < values.length; i++) { + traverse(values[i], seen) + } } else { - for (const key in value) { - traverse(value[key], seen) + const keys = [ + ...Object.getOwnPropertyNames(value), + ...Object.getOwnPropertySymbols(value) + ] + + for (let i = 0; i < keys.length; i++) { + // TS doesn't allow symbol as index type + traverse(value[keys[i] as string], seen) } } return value