Skip to content

Commit c67a710

Browse files
committed
avoid triggering watcher on unchanged default props (fix #4090) (26 seconds ago)
1 parent 6e3e989 commit c67a710

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed

src/core/instance/lifecycle.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ export function lifecycleMixin (Vue: Class<Component>) {
132132
if (process.env.NODE_ENV !== 'production') {
133133
observerState.isSettingProps = false
134134
}
135+
vm.$options.propsData = propsData
135136
}
136137
// update listeners
137138
if (listeners) {

src/core/util/props.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function validateProp (
4747
/**
4848
* Get the default value of a prop.
4949
*/
50-
function getPropDefaultValue (vm: ?Component, prop: PropOptions, name: string): any {
50+
function getPropDefaultValue (vm: ?Component, prop: PropOptions, key: string): any {
5151
// no default, return undefined
5252
if (!hasOwn(prop, 'default')) {
5353
return undefined
@@ -56,12 +56,19 @@ function getPropDefaultValue (vm: ?Component, prop: PropOptions, name: string):
5656
// warn against non-factory defaults for Object & Array
5757
if (isObject(def)) {
5858
process.env.NODE_ENV !== 'production' && warn(
59-
'Invalid default value for prop "' + name + '": ' +
59+
'Invalid default value for prop "' + key + '": ' +
6060
'Props with type Object/Array must use a factory function ' +
6161
'to return the default value.',
6262
vm
6363
)
6464
}
65+
// the raw prop value was also undefined from previous render,
66+
// return previous default value to avoid unnecessary watcher trigger
67+
if (vm && vm.$options.propsData &&
68+
vm.$options.propsData[key] === undefined &&
69+
vm[key] !== undefined) {
70+
return vm[key]
71+
}
6572
// call factory function for non-Function types
6673
return typeof def === 'function' && prop.type !== Function
6774
? def.call(vm)

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,4 +399,46 @@ describe('Options props', () => {
399399
expect(spy).not.toHaveBeenCalled()
400400
}).then(done)
401401
})
402+
403+
// #4090
404+
it('should not trigger wathcer on default value', done => {
405+
const spy = jasmine.createSpy()
406+
const vm = new Vue({
407+
template: `<test :value="a" :test="b"></test>`,
408+
data: {
409+
a: 1,
410+
b: undefined
411+
},
412+
components: {
413+
test: {
414+
template: '<div>{{ value }}</div>',
415+
props: {
416+
value: { type: Number },
417+
test: {
418+
type: Object,
419+
default: () => ({})
420+
}
421+
},
422+
watch: {
423+
test: spy
424+
}
425+
}
426+
}
427+
}).$mount()
428+
429+
vm.a++
430+
waitForUpdate(() => {
431+
expect(spy).not.toHaveBeenCalled()
432+
vm.b = {}
433+
}).then(() => {
434+
expect(spy.calls.count()).toBe(1)
435+
}).then(() => {
436+
vm.b = undefined
437+
}).then(() => {
438+
expect(spy.calls.count()).toBe(2)
439+
vm.a++
440+
}).then(() => {
441+
expect(spy.calls.count()).toBe(2)
442+
}).then(done)
443+
})
402444
})

0 commit comments

Comments
 (0)