fix(reactivity): track reactive keys in raw collection types

Also warn against presence of both raw and reactive versions of the
same object in a collection as keys.

fix #919
This commit is contained in:
Evan You
2020-04-04 12:57:15 -04:00
parent 7402951d94
commit 5dcc645fc0
3 changed files with 126 additions and 6 deletions

View File

@@ -1,7 +1,10 @@
import { reactive, effect, toRaw, isReactive } from '../../src'
import { mockWarn } from '@vue/shared'
describe('reactivity/collections', () => {
describe('Map', () => {
mockWarn()
test('instanceof', () => {
const original = new Map()
const observed = reactive(original)
@@ -363,6 +366,51 @@ describe('reactivity/collections', () => {
expect(map.get(key)).toBeUndefined()
})
it('should track set of reactive keys in raw map', () => {
const raw = new Map()
const key = reactive({})
raw.set(key, 1)
const map = reactive(raw)
let dummy
effect(() => {
dummy = map.get(key)
})
expect(dummy).toBe(1)
map.set(key, 2)
expect(dummy).toBe(2)
})
it('should track deletion of reactive keys in raw map', () => {
const raw = new Map()
const key = reactive({})
raw.set(key, 1)
const map = reactive(raw)
let dummy
effect(() => {
dummy = map.has(key)
})
expect(dummy).toBe(true)
map.delete(key)
expect(dummy).toBe(false)
})
it('should warn when both raw and reactive versions of the same object is used as key', () => {
const raw = new Map()
const rawKey = {}
const key = reactive(rawKey)
raw.set(rawKey, 1)
raw.set(key, 1)
const map = reactive(raw)
map.set(key, 2)
expect(
`Reactive Map contains both the raw and reactive`
).toHaveBeenWarned()
})
// #877
it('should not trigger key iteration when setting existing keys', () => {
const map = reactive(new Map())

View File

@@ -1,7 +1,10 @@
import { reactive, effect, isReactive, toRaw } from '../../src'
import { mockWarn } from '@vue/shared'
describe('reactivity/collections', () => {
describe('Set', () => {
mockWarn()
it('instanceof', () => {
const original = new Set()
const observed = reactive(original)
@@ -380,5 +383,34 @@ describe('reactivity/collections', () => {
expect(set.delete(entry)).toBe(true)
expect(set.has(entry)).toBe(false)
})
it('should track deletion of reactive entries in raw set', () => {
const raw = new Set()
const entry = reactive({})
raw.add(entry)
const set = reactive(raw)
let dummy
effect(() => {
dummy = set.has(entry)
})
expect(dummy).toBe(true)
set.delete(entry)
expect(dummy).toBe(false)
})
it('should warn when set contains both raw and reactive versions of the same object', () => {
const raw = new Set()
const rawKey = {}
const key = reactive(rawKey)
raw.add(rawKey)
raw.add(key)
const set = reactive(raw)
set.delete(key)
expect(
`Reactive Set contains both the raw and reactive`
).toHaveBeenWarned()
})
})
})