Skip to content

Commit

Permalink
fix(reactivity): readonly+reactive collection should also expose read…
Browse files Browse the repository at this point in the history
…only+reactive values

fix #1772
  • Loading branch information
yyx990803 committed Aug 6, 2020
1 parent 48576e5 commit ed43810
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 12 deletions.
38 changes: 38 additions & 0 deletions packages/reactivity/__tests__/readonly.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,22 @@ describe('reactivity/readonly', () => {
).toHaveBeenWarned()
})

// #1772
test('readonly + reactive should make get() value also readonly + reactive', () => {
const map = reactive(new Collection())
const roMap = readonly(map)
const key = {}
map.set(key, {})

const item = map.get(key)
expect(isReactive(item)).toBe(true)
expect(isReadonly(item)).toBe(false)

const roItem = roMap.get(key)
expect(isReactive(roItem)).toBe(true)
expect(isReadonly(roItem)).toBe(true)
})

if (Collection === Map) {
test('should retrieve readonly values on iteration', () => {
const key1 = {}
Expand All @@ -223,6 +239,28 @@ describe('reactivity/readonly', () => {
expect(isReadonly(value)).toBe(true)
}
})

test('should retrieve reactive + readonly values on iteration', () => {
const key1 = {}
const key2 = {}
const original = reactive(new Collection([[key1, {}], [key2, {}]]))
const wrapped: any = readonly(original)
expect(wrapped.size).toBe(2)
for (const [key, value] of wrapped) {
expect(isReadonly(key)).toBe(true)
expect(isReadonly(value)).toBe(true)
expect(isReactive(key)).toBe(true)
expect(isReactive(value)).toBe(true)
}
wrapped.forEach((value: any) => {
expect(isReadonly(value)).toBe(true)
expect(isReactive(value)).toBe(true)
})
for (const value of wrapped.values()) {
expect(isReadonly(value)).toBe(true)
expect(isReactive(value)).toBe(true)
}
})
}
})
})
Expand Down
28 changes: 16 additions & 12 deletions packages/reactivity/src/collectionHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,20 @@ function get(
key: unknown,
wrap: typeof toReactive | typeof toReadonly | typeof toShallow
) {
target = toRaw(target)
// #1772: readonly(reactive(Map)) should return readonly + reactive version
// of the value
target = (target as any)[ReactiveFlags.RAW]
const rawTarget = toRaw(target)
const rawKey = toRaw(key)
if (key !== rawKey) {
track(target, TrackOpTypes.GET, key)
track(rawTarget, TrackOpTypes.GET, key)
}
track(target, TrackOpTypes.GET, rawKey)
const { has, get } = getProto(target)
if (has.call(target, key)) {
return wrap(get.call(target, key))
} else if (has.call(target, rawKey)) {
return wrap(get.call(target, rawKey))
track(rawTarget, TrackOpTypes.GET, rawKey)
const { has } = getProto(rawTarget)
if (has.call(rawTarget, key)) {
return wrap(target.get(key))
} else if (has.call(rawTarget, rawKey)) {
return wrap(target.get(rawKey))
}
}

Expand Down Expand Up @@ -176,15 +179,16 @@ function createIterableMethod(
this: IterableCollections,
...args: unknown[]
): Iterable & Iterator {
const target = toRaw(this)
const isMap = target instanceof Map
const target = (this as any)[ReactiveFlags.RAW]
const rawTarget = toRaw(this)
const isMap = rawTarget instanceof Map
const isPair = method === 'entries' || (method === Symbol.iterator && isMap)
const isKeyOnly = method === 'keys' && isMap
const innerIterator = getProto(target)[method].apply(target, args)
const innerIterator = target[method](...args)
const wrap = isReadonly ? toReadonly : shallow ? toShallow : toReactive
!isReadonly &&
track(
target,
rawTarget,
TrackOpTypes.ITERATE,
isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY
)
Expand Down

0 comments on commit ed43810

Please sign in to comment.