Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/core/instance/lifecycle.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { mark, measure } from '../util/perf'
import { createEmptyVNode } from '../vdom/vnode'
import { updateComponentListeners } from './events'
import { resolveSlots } from './render-helpers/resolve-slots'
import { toggleObserving } from '../observer/index'
import { toggleObserving, toggleNotifyingSubscribers } from '../observer/index'
import { pushTarget, popTarget } from '../observer/dep'

import {
Expand Down Expand Up @@ -257,8 +257,13 @@ export function updateChildComponent (
// update $attrs and $listeners hash
// these are also reactive so they may trigger child update if the child
// used them during render
vm.$attrs = parentVnode.data.attrs || emptyObject

// Disable subscribers notification in setter to avoid rerendering a child that uses $listeners
toggleNotifyingSubscribers(false)
vm.$listeners = listeners || emptyObject
toggleNotifyingSubscribers(true)

vm.$attrs = parentVnode.data.attrs || emptyObject

// update props
if (propsData && vm.$options.props) {
Expand Down
13 changes: 12 additions & 1 deletion src/core/observer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ export function toggleObserving (value: boolean) {
shouldObserve = value
}

/**
* In some cases we may want to disable the run of all subscribers
* inside a component's update computation.
*/
export let shouldNotifySubscribers: boolean = true


export function toggleNotifyingSubscribers (value: boolean) {
shouldNotifySubscribers = value
}

/**
* Observer class that is attached to each observed
* object. Once attached, the observer converts the target
Expand Down Expand Up @@ -188,7 +199,7 @@ export function defineReactive (
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify()
shouldNotifySubscribers && dep.notify()
}
})
}
Expand Down
36 changes: 36 additions & 0 deletions test/unit/features/instance/properties.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,42 @@ describe('Instance properties', () => {
}).then(done)
})

// #7257 Do not rerender child components that use $listeners when the parent component gets updated
it('parent component update should not rerender child component with listeners', done => {
const spyA = jasmine.createSpy('A')
const spyB = jasmine.createSpy('B')
const vm = new Vue({
template: `<div><foo v-model="foo"/> <bar v-model="bar"/></div>`,
data: { foo: 'foo', bar: 'bar' },
components: {
foo: {
props: {
value: String
},
template: `<div><input v-on="$listeners" id="foo" v-bind:value="value" /></div>`,
updated() {
spyA()
}
},
bar: {
props: {
value: String
},
template: `<div><input v-on="$listeners" v-bind:value="value" /></div>`,
updated() {
spyB()
}
}
}
}).$mount()

vm.foo = 'new foo'
waitForUpdate(() => {
expect(spyA.calls.count()).toBe(1)
expect(spyB.calls.count()).toBe(0)
}).then(done)
})

it('warn mutating $listeners', () => {
const vm = new Vue()
vm.$listeners = {}
Expand Down