Skip to content

Commit

Permalink
prohibit replacing $data
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jun 16, 2016
1 parent c1a523d commit 2bb1504
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 91 deletions.
57 changes: 23 additions & 34 deletions src/core/instance/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

import Watcher from '../observer/watcher'
import Dep from '../observer/dep'

import {
observe,
defineReactive,
observerState,
proxy,
unproxy
observerState
} from '../observer/index'

import {
warn,
hasOwn,
isReserved,
isPlainObject,
bind,
validateProp,
Expand Down Expand Up @@ -180,9 +181,13 @@ export function stateMixin (Vue: Class<Component>) {
dataDef.get = function () {
return this._data
}
dataDef.set = function (newData: Object) {
if (newData !== this._data) {
setData(this, newData)
if (process.env.NODE_ENV !== 'production') {
dataDef.set = function (newData: Object) {
warn(
'Avoid replacing instance root $data. ' +
'Use nested data properties instead.',
this
)
}
}
Object.defineProperty(Vue.prototype, '$data', dataDef)
Expand All @@ -205,33 +210,17 @@ export function stateMixin (Vue: Class<Component>) {
}
}

function setData (vm: Component, newData: Object) {
newData = newData || {}
const oldData = vm._data
vm._data = newData
let keys, key, i
// unproxy keys not present in new data
keys = Object.keys(oldData)
i = keys.length
while (i--) {
key = keys[i]
if (!(key in newData)) {
unproxy(vm, key)
}
}
// proxy keys not already proxied,
// and trigger change for changed values
keys = Object.keys(newData)
i = keys.length
while (i--) {
key = keys[i]
if (!hasOwn(vm, key)) {
// new property
proxy(vm, key)
}
function proxy (vm: Component, key: string) {
if (!isReserved(key)) {
Object.defineProperty(vm, key, {
configurable: true,
enumerable: true,
get: function proxyGetter () {
return vm._data[key]
},
set: function proxySetter (val) {
vm._data[key] = val
}
})
}
oldData.__ob__ && oldData.__ob__.vmCount--
observe(newData)
newData.__ob__ && newData.__ob__.vmCount++
vm.$forceUpdate()
}
23 changes: 0 additions & 23 deletions src/core/observer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
isPlainObject,
hasProto,
hasOwn,
isReserved,
warn
} from '../util/index'

Expand Down Expand Up @@ -235,25 +234,3 @@ export function del (obj: Object, key: string) {
}
ob.dep.notify()
}

export function proxy (vm: Component, key: string) {
if (!isReserved(key)) {
Object.defineProperty(vm, key, {
configurable: true,
enumerable: true,
get: function proxyGetter () {
return vm._data[key]
},
set: function proxySetter (val) {
vm._data[key] = val
}
})
}
}

// using Object type to avoid flow complaining
export function unproxy (vm: Component, key: string) {
if (!isReserved(key)) {
delete vm[key]
}
}
8 changes: 8 additions & 0 deletions test/unit/features/options/data.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,12 @@ describe('Options data', () => {
})
expect('data functions should return an object').toHaveBeenWarned()
})

it('should warn replacing root $data', () => {
const vm = new Vue({
data: {}
})
vm.$data = {}
expect('Avoid replacing instance root $data').toHaveBeenWarned()
})
})
17 changes: 0 additions & 17 deletions test/unit/features/options/watch.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,4 @@ describe('Options watch', () => {
expect(spy).toHaveBeenCalledWith(vm.a, oldA)
}).then(done)
})

it('replace $data', done => {
const vm = new Vue({
data: {
a: 1
},
watch: {
a: spy
}
})
expect(spy).not.toHaveBeenCalled()
vm.$data = { a: 2 }
expect(spy).not.toHaveBeenCalled()
waitForUpdate(() => {
expect(spy).toHaveBeenCalledWith(2, 1)
}).then(done)
})
})
17 changes: 0 additions & 17 deletions test/unit/modules/observer/watcher.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,6 @@ describe('Watcher', () => {
}).then(done)
})

it('swapping $data', done => {
// existing path
const watcher1 = new Watcher(vm, 'b.c', spy)
// non-existing path
const spy2 = jasmine.createSpy()
const watcher2 = new Watcher(vm, 'e', spy2)
expect(watcher1.value).toBe(2)
expect(watcher2.value).toBeUndefined()
vm.$data = { b: { c: 3 }, e: 4 }
waitForUpdate(() => {
expect(watcher1.value).toBe(3)
expect(watcher2.value).toBe(4)
expect(spy).toHaveBeenCalledWith(3, 2)
expect(spy2).toHaveBeenCalledWith(4, undefined)
}).then(done)
})

it('path containing $data', done => {
const watcher = new Watcher(vm, '$data.b.c', spy)
expect(watcher.value).toBeUndefined()
Expand Down

0 comments on commit 2bb1504

Please sign in to comment.