Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(reactivity): shallowReactive map "unwraps" the nested refs #8503

Merged
merged 5 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions packages/reactivity/__tests__/reactive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { isRef, ref } from '../src/ref'
import {
isProxy,
isReactive,
isReadonly,
isShallow,
markRaw,
reactive,
readonly,
Expand Down Expand Up @@ -359,4 +361,25 @@ describe('reactivity/reactive', () => {
const c = computed(() => {})
expect(isProxy(c)).toBe(false)
})

test('The results of the shallow and readonly assignments are the same (Map)', () => {
const map = reactive(new Map())
map.set('foo', shallowReactive({ a: 2 }))
expect(isShallow(map.get('foo'))).toBe(true)

map.set('bar', readonly({ b: 2 }))
expect(isReadonly(map.get('bar'))).toBe(true)
})

test('The results of the shallow and readonly assignments are the same (Set)', () => {
const set = reactive(new Set())
set.add(shallowReactive({ a: 2 }))
set.add(readonly({ b: 2 }))
let count = 0
for (const i of set) {
if (count === 0) expect(isShallow(i)).toBe(true)
else expect(isReadonly(i)).toBe(true)
count++
}
})
})
23 changes: 23 additions & 0 deletions packages/reactivity/__tests__/shallowReactive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,29 @@ describe('shallowReactive', () => {
shallowSet.forEach(x => expect(isReactive(x)).toBe(false))
})

test('Setting a reactive object on a shallowReactive map', () => {
const msg = ref('ads')
const bar = reactive({ msg })
const foo = shallowReactive(new Map([['foo1', bar]]))
foo.set('foo2', bar)

expect(isReactive(foo.get('foo2'))).toBe(true)
expect(isReactive(foo.get('foo1'))).toBe(true)
})

test('Setting a reactive object on a shallowReactive set', () => {
const msg = ref(1)
const bar = reactive({ msg })
const foo = reactive({ msg })

const deps = shallowReactive(new Set([bar]))
deps.add(foo)

deps.forEach(dep => {
expect(isReactive(dep)).toBe(true)
})
})

// #1210
test('onTrack on called on objectSpread', () => {
const onTrackFn = vi.fn()
Expand Down
28 changes: 21 additions & 7 deletions packages/reactivity/src/collectionHandlers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { toRaw, toReactive, toReadonly } from './reactive'
import {
isReadonly,
isShallow,
toRaw,
toReactive,
toReadonly,
} from './reactive'
import {
ITERATE_KEY,
MAP_KEY_ITERATE_KEY,
Expand Down Expand Up @@ -72,8 +78,10 @@ function size(target: IterableCollections, isReadonly = false) {
return Reflect.get(target, 'size', target)
}

function add(this: SetTypes, value: unknown) {
value = toRaw(value)
function add(this: SetTypes, value: unknown, _isShallow = false) {
if (!_isShallow && !isShallow(value) && !isReadonly(value)) {
value = toRaw(value)
}
const target = toRaw(this)
const proto = getProto(target)
const hadKey = proto.has.call(target, value)
Expand All @@ -84,8 +92,10 @@ function add(this: SetTypes, value: unknown) {
return this
}

function set(this: MapTypes, key: unknown, value: unknown) {
value = toRaw(value)
function set(this: MapTypes, key: unknown, value: unknown, _isShallow = false) {
if (!_isShallow && !isShallow(value) && !isReadonly(value)) {
value = toRaw(value)
}
const target = toRaw(this)
const { has, get } = getProto(target)

Expand Down Expand Up @@ -263,8 +273,12 @@ function createInstrumentations() {
return size(this as unknown as IterableCollections)
},
has,
add,
set,
add(this: SetTypes, value: unknown) {
return add.call(this, value, true)
},
set(this: MapTypes, key: unknown, value: unknown) {
return set.call(this, key, value, true)
},
delete: deleteEntry,
clear,
forEach: createForEach(false, true),
Expand Down