fix(reactivity): fix shallowReactive nested ref setting edge cases

ref #12688
This commit is contained in:
Evan You 2022-07-22 11:19:34 +08:00
parent ba7dd2c4ed
commit 2af751b6ef
4 changed files with 39 additions and 7 deletions

View File

@ -191,7 +191,7 @@ export function defineReactive(
} else if (getter) {
// #7981: for accessor properties without setter
return
} else if (isRef(value) && !isRef(newVal)) {
} else if (!shallow && isRef(value) && !isRef(newVal)) {
value.value = newVal
return
} else {

View File

@ -483,7 +483,6 @@ describe('reactivity/readonly', () => {
const ror = readonly(r)
const obj = reactive({ ror })
obj.ror = true
expect(obj.ror).toBe(false)
expect(`Set operation on key "value" failed`).toHaveBeenWarned()
})
@ -492,14 +491,20 @@ describe('reactivity/readonly', () => {
const r = ref(false)
const ror = readonly(r)
const obj = reactive({ ror })
try {
obj.ror = ref(true) as unknown as boolean
} catch (e) {}
obj.ror = ref(true) as unknown as boolean
expect(obj.ror).toBe(true)
expect(toRaw(obj).ror).not.toBe(ror) // ref successfully replaced
})
test('setting readonly object to writable nested ref', () => {
const r = ref<any>()
const obj = reactive({ r })
const ro = readonly({})
obj.r = ro
expect(obj.r).toBe(ro)
expect(r.value).toBe(ro)
})
test('compatiblity with classes', () => {
const spy = vi.fn()
class Foo {

View File

@ -11,7 +11,8 @@ import {
isReactive,
isShallow,
reactive,
computed
computed,
readonly
} from 'v3'
import { effect } from 'v3/reactivity/effect'
@ -404,4 +405,17 @@ describe('reactivity/ref', () => {
b.value = obj
expect(spy2).toBeCalledTimes(1)
})
test('ref should preserve value readonly-ness', () => {
const original = {}
const r = reactive(original)
const rr = readonly(original)
const a = ref(original)
expect(a.value).toBe(r)
a.value = rr
expect(a.value).toBe(rr)
expect(a.value).not.toBe(r)
})
})

View File

@ -3,6 +3,7 @@ import {
isRef,
isShallow,
reactive,
Ref,
ref,
shallowReactive,
shallowReadonly
@ -45,6 +46,18 @@ describe('shallowReactive', () => {
expect(foo.bar.value).toBe(123)
})
// #12688
test('should not mutate refs', () => {
const original = ref(123)
const foo = shallowReactive<{ bar: Ref<number> | number }>({
bar: original
})
expect(foo.bar).toBe(original)
foo.bar = 234
expect(foo.bar).toBe(234)
expect(original.value).toBe(123)
})
// @discrepancy no shallow/non-shallow versions from the same source -
// cannot support this without real proxies
// #2843