Skip to content

Commit d1788b9

Browse files
committed
props refactor
- No need to merge props into the data object. they should just be defined as reactive properties on the vm instance. - They should not observe the value when set. They should already be reactive if needed.
1 parent e230cb7 commit d1788b9

File tree

6 files changed

+33
-74
lines changed

6 files changed

+33
-74
lines changed

src/instance/internal/init.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,6 @@ export default function (Vue) {
8080
this.$parent.$children.push(this)
8181
}
8282

83-
// save raw constructor data before merge
84-
// so that we know which properties are provided at
85-
// instantiation.
86-
if (process.env.NODE_ENV !== 'production') {
87-
this._runtimeData = options.data
88-
}
89-
9083
// merge options.
9184
options = this.$options = mergeOptions(
9285
this.constructor.options,
@@ -101,6 +94,11 @@ export default function (Vue) {
10194
// it will be filled up in _initScope().
10295
this._data = {}
10396

97+
// save raw constructor data before merge
98+
// so that we know which properties are provided at
99+
// instantiation.
100+
this._runtimeData = options.data
101+
104102
// call init hook
105103
this._callHook('init')
106104

src/instance/internal/state.js

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
warn,
1111
query,
1212
hasOwn,
13-
set,
1413
isReserved,
1514
bind
1615
} from '../../util/index'
@@ -76,41 +75,35 @@ export default function (Vue) {
7675
*/
7776

7877
Vue.prototype._initData = function () {
79-
var propsData = this._data
80-
var optionsDataFn = this.$options.data
81-
var optionsData = optionsDataFn && optionsDataFn()
82-
var runtimeData
83-
if (process.env.NODE_ENV !== 'production') {
84-
runtimeData = (typeof this._runtimeData === 'function'
78+
var dataFn = this.$options.data
79+
var data = this._data = dataFn ? dataFn() : {}
80+
var props = this._props
81+
var runtimeData = this._runtimeData
82+
? typeof this._runtimeData === 'function'
8583
? this._runtimeData()
86-
: this._runtimeData) || {}
87-
this._runtimeData = null
88-
}
89-
if (optionsData) {
90-
this._data = optionsData
91-
for (var prop in propsData) {
92-
if (process.env.NODE_ENV !== 'production' &&
93-
hasOwn(optionsData, prop) &&
94-
!hasOwn(runtimeData, prop)) {
95-
warn(
96-
'Data field "' + prop + '" is already defined ' +
97-
'as a prop. Use prop default value instead.'
98-
)
99-
}
100-
if (this._props[prop].raw !== null ||
101-
!hasOwn(optionsData, prop)) {
102-
set(optionsData, prop, propsData[prop])
103-
}
104-
}
105-
}
106-
var data = this._data
84+
: this._runtimeData
85+
: null
10786
// proxy data on instance
10887
var keys = Object.keys(data)
10988
var i, key
11089
i = keys.length
11190
while (i--) {
11291
key = keys[i]
113-
this._proxy(key)
92+
// there are two scenarios where we can proxy a data key:
93+
// 1. it's not already defined as a prop
94+
// 2. it's provided via a instantiation option AND there are no
95+
// template prop present
96+
if (
97+
!props || !hasOwn(props, key) ||
98+
(runtimeData && hasOwn(runtimeData, key) && props[key].raw === null)
99+
) {
100+
this._proxy(key)
101+
} else if (process.env.NODE_ENV !== 'production') {
102+
warn(
103+
'Data field "' + key + '" is already defined ' +
104+
'as a prop. Use prop default value instead.'
105+
)
106+
}
114107
}
115108
// observe data
116109
observe(data, this)

src/util/component.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { warn } from './debug'
22
import { resolveAsset } from './options'
33
import { getAttr, getBindAttr } from './dom'
44
import { isArray, isPlainObject, isObject, hasOwn } from './lang'
5+
import { defineReactive } from '../observer/index'
56

67
export const commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i
78
export const reservedTagRE = /^(slot|partial|component)$/i
@@ -103,9 +104,9 @@ export function initProp (vm, prop, value) {
103104
if (value === undefined) {
104105
value = getPropDefaultValue(vm, prop.options)
105106
}
106-
vm[key] = vm._data[key] = assertProp(prop, value)
107-
? value
108-
: undefined
107+
if (assertProp(prop, value)) {
108+
defineReactive(vm, key, value, true /* doNotObserve */)
109+
}
109110
}
110111

111112
/**

test/unit/specs/compiler/compile_spec.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -299,18 +299,12 @@ describe('Compile', function () {
299299
expect(vm._bindDir.calls.count()).toBe(4)
300300
// literal
301301
expect(vm.testLiteral).toBe('1')
302-
expect(vm._data.testLiteral).toBe('1')
303302
expect(vm.testBoolean).toBe(true)
304-
expect(vm._data.testBoolean).toBe(true)
305303
expect(vm.optimizeLiteral).toBe(1)
306-
expect(vm._data.optimizeLiteral).toBe(1)
307304
expect(vm.optimizeLiteralStr).toBe('true')
308-
expect(vm._data.optimizeLiteralStr).toBe('true')
309305
expect(vm.optimizeLiteralNegativeNumber).toBe(-1)
310-
expect(vm._data.optimizeLiteralNegativeNumber).toBe(-1)
311306
// one time
312307
expect(vm.testOneTime).toBe('from parent: a')
313-
expect(vm._data.testOneTime).toBe('from parent: a')
314308
// normal
315309
var args = vm._bindDir.calls.argsFor(0)
316310
var prop = args[0].prop
@@ -345,8 +339,8 @@ describe('Compile', function () {
345339
el.setAttribute(':b', '[1,2,3]')
346340
compiler.compileAndLinkProps(vm, el, { a: null, b: null })
347341
expect(vm._bindDir.calls.count()).toBe(0)
348-
expect(vm._data.a).toBe('hi')
349-
expect(vm._data.b.join(',')).toBe('1,2,3')
342+
expect(vm.a).toBe('hi')
343+
expect(vm.b.join(',')).toBe('1,2,3')
350344
// restore parent mock
351345
vm._context = context
352346
})

test/unit/specs/directives/internal/prop_spec.js

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -491,31 +491,6 @@ describe('prop', function () {
491491
expect(el.textContent).toBe('AAA')
492492
})
493493

494-
it('should not overwrite default value for an absent Boolean prop', function () {
495-
var vm = new Vue({
496-
el: el,
497-
template: '<test></test>',
498-
components: {
499-
test: {
500-
props: {
501-
prop: Boolean
502-
},
503-
data: function () {
504-
return {
505-
prop: true
506-
}
507-
},
508-
template: '{{prop}}'
509-
}
510-
}
511-
})
512-
expect(vm.$children[0].prop).toBe(true)
513-
expect(vm.$el.textContent).toBe('true')
514-
expect(JSON.stringify(vm.$children[0].$data)).toBe(JSON.stringify({
515-
prop: true
516-
}))
517-
})
518-
519494
it('should respect default value of a Boolean prop', function () {
520495
var vm = new Vue({
521496
el: el,

test/unit/specs/instance/state_spec.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,12 @@ describe('Instance state initialization', function () {
7272
props: ['c'],
7373
data: function () {
7474
expect(this.c).toBe(2)
75-
expect(this._data.c).toBe(2)
7675
return {
7776
d: this.c + 1
7877
}
7978
},
8079
created: function () {
8180
expect(this.c).toBe(2)
82-
expect(this._data.c).toBe(2)
8381
}
8482
})
8583
expect(vm.d).toBe(3)

0 commit comments

Comments
 (0)