From c86ca8c8a99f997731d46178f41ad1a4babe80d9 Mon Sep 17 00:00:00 2001 From: Helios Date: Thu, 6 Aug 2020 17:31:35 +0800 Subject: [PATCH 1/2] fix(reactivity): process subtypes of collections properly --- packages/reactivity/__tests__/reactive.spec.ts | 18 ++++++++++++++++++ packages/reactivity/src/reactive.ts | 14 ++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/reactivity/__tests__/reactive.spec.ts b/packages/reactivity/__tests__/reactive.spec.ts index b7f9cdf4eb3..ab798ff2c8b 100644 --- a/packages/reactivity/__tests__/reactive.spec.ts +++ b/packages/reactivity/__tests__/reactive.spec.ts @@ -44,6 +44,24 @@ describe('reactivity/reactive', () => { expect(isReactive(observed.array[0])).toBe(true) }) + test('process subtypes of collections properly', () => { + class CustomMap extends Map { + count = 0 + + set(key: any, value: any): this { + super.set(key, value) + this.count++ + return this + } + } + + const testMap = new CustomMap() + const observed = reactive(testMap) + expect(observed.count).toBe(0) + observed.set('test', 'value') + expect(observed.count).toBe(1) + }) + test('observed value should proxy mutations to original (Object)', () => { const original: any = { foo: 1 } const observed = reactive(original) diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index 4dea9e00c86..c3f874c0c31 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -151,10 +151,16 @@ function createReactiveObject( if (!canObserve(target)) { return target } - const observed = new Proxy( - target, - collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers - ) + + let handler = baseHandlers + for (const collectionType of collectionTypes) { + if (target instanceof collectionType) { + handler = collectionHandlers + break + } + } + + const observed = new Proxy(target, handler) def(target, reactiveFlag, observed) return observed } From 6ebca67530728f08b18bc96b4792ca2ee915b143 Mon Sep 17 00:00:00 2001 From: Helios Date: Thu, 6 Aug 2020 20:29:07 +0800 Subject: [PATCH 2/2] fix(reactivity): check collection type efficiently --- packages/reactivity/src/reactive.ts | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index c3f874c0c31..e7db1e0a071 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -18,7 +18,9 @@ export const enum ReactiveFlags { IS_READONLY = '__v_isReadonly', RAW = '__v_raw', REACTIVE = '__v_reactive', - READONLY = '__v_readonly' + READONLY = '__v_readonly', + + IS_COLLECTION = '__v_isCollection' } interface Target { @@ -28,9 +30,15 @@ interface Target { [ReactiveFlags.RAW]?: any [ReactiveFlags.REACTIVE]?: any [ReactiveFlags.READONLY]?: any + + [ReactiveFlags.IS_COLLECTION]?: boolean } -const collectionTypes = new Set([Set, Map, WeakMap, WeakSet]) +;([Set, Map, WeakMap, WeakSet] as Array).forEach( + collectionType => + (collectionType.prototype[ReactiveFlags.IS_COLLECTION] = true) +) + const isObservableType = /*#__PURE__*/ makeMap( 'Object,Array,Map,Set,WeakMap,WeakSet' ) @@ -152,15 +160,10 @@ function createReactiveObject( return target } - let handler = baseHandlers - for (const collectionType of collectionTypes) { - if (target instanceof collectionType) { - handler = collectionHandlers - break - } - } - - const observed = new Proxy(target, handler) + const observed = new Proxy( + target, + target[ReactiveFlags.IS_COLLECTION] ? collectionHandlers : baseHandlers + ) def(target, reactiveFlag, observed) return observed }