Skip to content

Commit 2bb1504

Browse files
committed
prohibit replacing $data
1 parent c1a523d commit 2bb1504

File tree

5 files changed

+31
-91
lines changed

5 files changed

+31
-91
lines changed

src/core/instance/state.js

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22

33
import Watcher from '../observer/watcher'
44
import Dep from '../observer/dep'
5+
56
import {
67
observe,
78
defineReactive,
8-
observerState,
9-
proxy,
10-
unproxy
9+
observerState
1110
} from '../observer/index'
11+
1212
import {
1313
warn,
1414
hasOwn,
15+
isReserved,
1516
isPlainObject,
1617
bind,
1718
validateProp,
@@ -180,9 +181,13 @@ export function stateMixin (Vue: Class<Component>) {
180181
dataDef.get = function () {
181182
return this._data
182183
}
183-
dataDef.set = function (newData: Object) {
184-
if (newData !== this._data) {
185-
setData(this, newData)
184+
if (process.env.NODE_ENV !== 'production') {
185+
dataDef.set = function (newData: Object) {
186+
warn(
187+
'Avoid replacing instance root $data. ' +
188+
'Use nested data properties instead.',
189+
this
190+
)
186191
}
187192
}
188193
Object.defineProperty(Vue.prototype, '$data', dataDef)
@@ -205,33 +210,17 @@ export function stateMixin (Vue: Class<Component>) {
205210
}
206211
}
207212

208-
function setData (vm: Component, newData: Object) {
209-
newData = newData || {}
210-
const oldData = vm._data
211-
vm._data = newData
212-
let keys, key, i
213-
// unproxy keys not present in new data
214-
keys = Object.keys(oldData)
215-
i = keys.length
216-
while (i--) {
217-
key = keys[i]
218-
if (!(key in newData)) {
219-
unproxy(vm, key)
220-
}
221-
}
222-
// proxy keys not already proxied,
223-
// and trigger change for changed values
224-
keys = Object.keys(newData)
225-
i = keys.length
226-
while (i--) {
227-
key = keys[i]
228-
if (!hasOwn(vm, key)) {
229-
// new property
230-
proxy(vm, key)
231-
}
213+
function proxy (vm: Component, key: string) {
214+
if (!isReserved(key)) {
215+
Object.defineProperty(vm, key, {
216+
configurable: true,
217+
enumerable: true,
218+
get: function proxyGetter () {
219+
return vm._data[key]
220+
},
221+
set: function proxySetter (val) {
222+
vm._data[key] = val
223+
}
224+
})
232225
}
233-
oldData.__ob__ && oldData.__ob__.vmCount--
234-
observe(newData)
235-
newData.__ob__ && newData.__ob__.vmCount++
236-
vm.$forceUpdate()
237226
}

src/core/observer/index.js

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
isPlainObject,
1010
hasProto,
1111
hasOwn,
12-
isReserved,
1312
warn
1413
} from '../util/index'
1514

@@ -235,25 +234,3 @@ export function del (obj: Object, key: string) {
235234
}
236235
ob.dep.notify()
237236
}
238-
239-
export function proxy (vm: Component, key: string) {
240-
if (!isReserved(key)) {
241-
Object.defineProperty(vm, key, {
242-
configurable: true,
243-
enumerable: true,
244-
get: function proxyGetter () {
245-
return vm._data[key]
246-
},
247-
set: function proxySetter (val) {
248-
vm._data[key] = val
249-
}
250-
})
251-
}
252-
}
253-
254-
// using Object type to avoid flow complaining
255-
export function unproxy (vm: Component, key: string) {
256-
if (!isReserved(key)) {
257-
delete vm[key]
258-
}
259-
}

test/unit/features/options/data.spec.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,12 @@ describe('Options data', () => {
6767
})
6868
expect('data functions should return an object').toHaveBeenWarned()
6969
})
70+
71+
it('should warn replacing root $data', () => {
72+
const vm = new Vue({
73+
data: {}
74+
})
75+
vm.$data = {}
76+
expect('Avoid replacing instance root $data').toHaveBeenWarned()
77+
})
7078
})

test/unit/features/options/watch.spec.js

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -101,21 +101,4 @@ describe('Options watch', () => {
101101
expect(spy).toHaveBeenCalledWith(vm.a, oldA)
102102
}).then(done)
103103
})
104-
105-
it('replace $data', done => {
106-
const vm = new Vue({
107-
data: {
108-
a: 1
109-
},
110-
watch: {
111-
a: spy
112-
}
113-
})
114-
expect(spy).not.toHaveBeenCalled()
115-
vm.$data = { a: 2 }
116-
expect(spy).not.toHaveBeenCalled()
117-
waitForUpdate(() => {
118-
expect(spy).toHaveBeenCalledWith(2, 1)
119-
}).then(done)
120-
})
121104
})

test/unit/modules/observer/watcher.spec.js

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,6 @@ describe('Watcher', () => {
5959
}).then(done)
6060
})
6161

62-
it('swapping $data', done => {
63-
// existing path
64-
const watcher1 = new Watcher(vm, 'b.c', spy)
65-
// non-existing path
66-
const spy2 = jasmine.createSpy()
67-
const watcher2 = new Watcher(vm, 'e', spy2)
68-
expect(watcher1.value).toBe(2)
69-
expect(watcher2.value).toBeUndefined()
70-
vm.$data = { b: { c: 3 }, e: 4 }
71-
waitForUpdate(() => {
72-
expect(watcher1.value).toBe(3)
73-
expect(watcher2.value).toBe(4)
74-
expect(spy).toHaveBeenCalledWith(3, 2)
75-
expect(spy2).toHaveBeenCalledWith(4, undefined)
76-
}).then(done)
77-
})
78-
7962
it('path containing $data', done => {
8063
const watcher = new Watcher(vm, '$data.b.c', spy)
8164
expect(watcher.value).toBeUndefined()

0 commit comments

Comments
 (0)