fix(reactivity): fix mutation on user proxy of reactive Array

close #9742
close #9751
close #9750
This commit is contained in:
Evan You 2023-12-07 13:26:30 +08:00
parent 983d45d4f8
commit 6ecbd5ce2a
3 changed files with 54 additions and 17 deletions

View File

@ -158,6 +158,21 @@ describe('reactivity/reactive', () => {
expect(original.bar).toBe(original2) expect(original.bar).toBe(original2)
}) })
// #1246
test('mutation on objects using reactive as prototype should not trigger', () => {
const observed = reactive({ foo: 1 })
const original = Object.create(observed)
let dummy
effect(() => (dummy = original.foo))
expect(dummy).toBe(1)
observed.foo = 2
expect(dummy).toBe(2)
original.foo = 3
expect(dummy).toBe(2)
original.foo = 4
expect(dummy).toBe(2)
})
test('toRaw', () => { test('toRaw', () => {
const original = { foo: 1 } const original = { foo: 1 }
const observed = reactive(original) const observed = reactive(original)
@ -166,11 +181,18 @@ describe('reactivity/reactive', () => {
}) })
test('toRaw on object using reactive as prototype', () => { test('toRaw on object using reactive as prototype', () => {
const original = reactive({}) const original = { foo: 1 }
const obj = Object.create(original) const observed = reactive(original)
const inherted = Object.create(observed)
expect(toRaw(inherted)).toBe(inherted)
})
test('toRaw on user Proxy wrapping reactive', () => {
const original = {}
const re = reactive(original)
const obj = new Proxy(re, {})
const raw = toRaw(obj) const raw = toRaw(obj)
expect(raw).toBe(obj) expect(raw).toBe(original)
expect(raw).not.toBe(toRaw(original))
}) })
test('should not unwrap Ref<T>', () => { test('should not unwrap Ref<T>', () => {

View File

@ -142,6 +142,15 @@ describe('reactivity/reactive/Array', () => {
expect(length).toBe('01') expect(length).toBe('01')
}) })
// #9742
test('mutation on user proxy of reactive Array', () => {
const array = reactive<number[]>([])
const proxy = new Proxy(array, {})
proxy.push(1)
expect(array).toHaveLength(1)
expect(proxy).toHaveLength(1)
})
describe('Array methods w/ refs', () => { describe('Array methods w/ refs', () => {
let original: any[] let original: any[]
beforeEach(() => { beforeEach(() => {

View File

@ -100,8 +100,8 @@ class BaseReactiveHandler implements ProxyHandler<Target> {
return isReadonly return isReadonly
} else if (key === ReactiveFlags.IS_SHALLOW) { } else if (key === ReactiveFlags.IS_SHALLOW) {
return shallow return shallow
} else if ( } else if (key === ReactiveFlags.RAW) {
key === ReactiveFlags.RAW && if (
receiver === receiver ===
(isReadonly (isReadonly
? shallow ? shallow
@ -110,10 +110,16 @@ class BaseReactiveHandler implements ProxyHandler<Target> {
: shallow : shallow
? shallowReactiveMap ? shallowReactiveMap
: reactiveMap : reactiveMap
).get(target) ).get(target) ||
// receiver is not the reactive proxy, but has the same prototype
// this means the reciever is a user proxy of the reactive proxy
Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)
) { ) {
return target return target
} }
// early return undefined
return
}
const targetIsArray = isArray(target) const targetIsArray = isArray(target)