diff --git a/src/core/instance/lifecycle.js b/src/core/instance/lifecycle.js index db7bf286f11..0ac1926e7e9 100644 --- a/src/core/instance/lifecycle.js +++ b/src/core/instance/lifecycle.js @@ -193,7 +193,10 @@ export function mountComponent ( } } - vm._watcher = new Watcher(vm, updateComponent, noop) + // we set this to vm._watcher inside the wathcer's constructor + // since the watcher's initial patch may call $forceUpdate (e.g. inside child + // component's mounted hook), which relies on vm._watcher being already defined + new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */) hydrating = false // manually mounted instance, call mounted on self diff --git a/src/core/observer/watcher.js b/src/core/observer/watcher.js index 3727bd53fb9..48a2e612e28 100644 --- a/src/core/observer/watcher.js +++ b/src/core/observer/watcher.js @@ -44,9 +44,13 @@ export default class Watcher { vm: Component, expOrFn: string | Function, cb: Function, - options?: Object + options?: ?Object, + isRenderWatcher?: boolean ) { this.vm = vm + if (isRenderWatcher) { + vm._watcher = this + } vm._watchers.push(this) // options if (options) { diff --git a/test/unit/features/component/component-async.spec.js b/test/unit/features/component/component-async.spec.js index a63b8c0e0da..889cb7145eb 100644 --- a/test/unit/features/component/component-async.spec.js +++ b/test/unit/features/component/component-async.spec.js @@ -342,5 +342,34 @@ describe('Component async', () => { done() }, 50) }) + + // #7107 + it(`should work when resolving sync in sibling component's mounted hook`, done => { + let resolveTwo + + const vm = new Vue({ + template: `
`, + components: { + one: { + template: `
one
`, + mounted () { + resolveTwo() + } + }, + two: resolve => { + resolveTwo = () => { + resolve({ + template: `
two
` + }) + } + } + } + }).$mount() + + expect(vm.$el.textContent).toBe('one ') + waitForUpdate(() => { + expect(vm.$el.textContent).toBe('one two') + }).then(done) + }) }) })