ensure updated hook is called after children are updated as well (fix #4599)

This commit is contained in:
Evan You 2016-12-29 16:19:44 -05:00
parent 299ecfc19f
commit 2ee516dfc8
4 changed files with 50 additions and 6 deletions

View File

@ -109,9 +109,8 @@ export function lifecycleMixin (Vue: Class<Component>) {
if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
vm.$parent.$el = vm.$el
}
if (vm._isMounted) {
callHook(vm, 'updated')
}
// updated hook is called by the scheduler to ensure that children are
// updated in a parent's updated hook.
}
Vue.prototype._updateFromParent = function (

View File

@ -2,6 +2,7 @@
import type Watcher from './watcher'
import config from '../config'
import { callHook } from '../instance/lifecycle'
import {
warn,
nextTick,
@ -32,6 +33,7 @@ function resetSchedulerState () {
*/
function flushSchedulerQueue () {
flushing = true
let watcher, id, vm
// Sort queue before flush.
// This ensures that:
@ -46,8 +48,8 @@ function flushSchedulerQueue () {
// do not cache length because more watchers might be pushed
// as we run existing watchers
for (index = 0; index < queue.length; index++) {
const watcher = queue[index]
const id = watcher.id
watcher = queue[index]
id = watcher.id
has[id] = null
watcher.run()
// in dev build, check and stop circular updates.
@ -67,6 +69,16 @@ function flushSchedulerQueue () {
}
}
// call updated hooks
index = queue.length
while (index--) {
watcher = queue[index]
vm = watcher.vm
if (vm._watcher === watcher && vm._isMounted) {
callHook(vm, 'updated')
}
}
// devtool hook
/* istanbul ignore if */
if (devtools && config.devtools) {

View File

@ -156,6 +156,34 @@ describe('Options lifecyce hooks', () => {
expect(spy).toHaveBeenCalled()
}).then(done)
})
it('should be called after children are updated', done => {
const calls = []
const vm = new Vue({
template: '<div><test ref="child">{{ msg }}</test></div>',
data: { msg: 'foo' },
components: {
test: {
template: `<div><slot></slot></div>`,
updated () {
expect(this.$el.textContent).toBe('bar')
calls.push('child')
}
}
},
updated () {
expect(this.$el.textContent).toBe('bar')
calls.push('parent')
}
}).$mount()
expect(calls).toEqual([])
vm.msg = 'bar'
expect(calls).toEqual([])
waitForUpdate(() => {
expect(calls).toEqual(['child', 'parent'])
}).then(done)
})
})
describe('beforeDestroy', () => {

View File

@ -1,6 +1,11 @@
import Vue from 'vue'
import config from 'core/config'
import { queueWatcher } from 'core/observer/scheduler'
import { queueWatcher as _queueWatcher } from 'core/observer/scheduler'
function queueWatcher (watcher) {
watcher.vm = {} // mock vm
_queueWatcher(watcher)
}
describe('Scheduler', () => {
let spy