Skip to content

Commit 6ecbd5c

Browse files
committedDec 7, 2023
fix(reactivity): fix mutation on user proxy of reactive Array
close #9742 close #9751 close #9750
1 parent 983d45d commit 6ecbd5c

File tree

3 files changed

+54
-17
lines changed

3 files changed

+54
-17
lines changed
 

‎packages/reactivity/__tests__/reactive.spec.ts

+26-4
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,21 @@ describe('reactivity/reactive', () => {
158158
expect(original.bar).toBe(original2)
159159
})
160160

161+
// #1246
162+
test('mutation on objects using reactive as prototype should not trigger', () => {
163+
const observed = reactive({ foo: 1 })
164+
const original = Object.create(observed)
165+
let dummy
166+
effect(() => (dummy = original.foo))
167+
expect(dummy).toBe(1)
168+
observed.foo = 2
169+
expect(dummy).toBe(2)
170+
original.foo = 3
171+
expect(dummy).toBe(2)
172+
original.foo = 4
173+
expect(dummy).toBe(2)
174+
})
175+
161176
test('toRaw', () => {
162177
const original = { foo: 1 }
163178
const observed = reactive(original)
@@ -166,11 +181,18 @@ describe('reactivity/reactive', () => {
166181
})
167182

168183
test('toRaw on object using reactive as prototype', () => {
169-
const original = reactive({})
170-
const obj = Object.create(original)
184+
const original = { foo: 1 }
185+
const observed = reactive(original)
186+
const inherted = Object.create(observed)
187+
expect(toRaw(inherted)).toBe(inherted)
188+
})
189+
190+
test('toRaw on user Proxy wrapping reactive', () => {
191+
const original = {}
192+
const re = reactive(original)
193+
const obj = new Proxy(re, {})
171194
const raw = toRaw(obj)
172-
expect(raw).toBe(obj)
173-
expect(raw).not.toBe(toRaw(original))
195+
expect(raw).toBe(original)
174196
})
175197

176198
test('should not unwrap Ref<T>', () => {

‎packages/reactivity/__tests__/reactiveArray.spec.ts

+9
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@ describe('reactivity/reactive/Array', () => {
142142
expect(length).toBe('01')
143143
})
144144

145+
// #9742
146+
test('mutation on user proxy of reactive Array', () => {
147+
const array = reactive<number[]>([])
148+
const proxy = new Proxy(array, {})
149+
proxy.push(1)
150+
expect(array).toHaveLength(1)
151+
expect(proxy).toHaveLength(1)
152+
})
153+
145154
describe('Array methods w/ refs', () => {
146155
let original: any[]
147156
beforeEach(() => {

‎packages/reactivity/src/baseHandlers.ts

+19-13
Original file line numberDiff line numberDiff line change
@@ -100,19 +100,25 @@ class BaseReactiveHandler implements ProxyHandler<Target> {
100100
return isReadonly
101101
} else if (key === ReactiveFlags.IS_SHALLOW) {
102102
return shallow
103-
} else if (
104-
key === ReactiveFlags.RAW &&
105-
receiver ===
106-
(isReadonly
107-
? shallow
108-
? shallowReadonlyMap
109-
: readonlyMap
110-
: shallow
111-
? shallowReactiveMap
112-
: reactiveMap
113-
).get(target)
114-
) {
115-
return target
103+
} else if (key === ReactiveFlags.RAW) {
104+
if (
105+
receiver ===
106+
(isReadonly
107+
? shallow
108+
? shallowReadonlyMap
109+
: readonlyMap
110+
: shallow
111+
? shallowReactiveMap
112+
: reactiveMap
113+
).get(target) ||
114+
// receiver is not the reactive proxy, but has the same prototype
115+
// this means the reciever is a user proxy of the reactive proxy
Has a conversation. Original line has a conversation.
116+
Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)
117+
) {
118+
return target
119+
}
120+
// early return undefined
121+
return
116122
}
117123

118124
const targetIsArray = isArray(target)

0 commit comments

Comments
 (0)
Please sign in to comment.