diff --git a/src/core/instance/init.ts b/src/core/instance/init.ts index 91456c219..3fdfcf4f0 100644 --- a/src/core/instance/init.ts +++ b/src/core/instance/init.ts @@ -1,6 +1,6 @@ import config from '../config' import { initProxy } from './proxy' -import { initState } from './state' +import { initProps, initState } from './state' import { initRender } from './render' import { initEvents } from './events' import { mark, measure } from '../util/perf' @@ -10,6 +10,7 @@ import { extend, mergeOptions, formatComponentName } from '../util/index' import type { Component } from 'types/component' import type { InternalComponentOptions } from 'types/options' import { EffectScope } from 'v3/reactivity/effectScope' +import { initSetup } from '../../v3/apiSetup' let uid = 0 @@ -59,8 +60,12 @@ export function initMixin(Vue: typeof Component) { initLifecycle(vm) initEvents(vm) initRender(vm) - callHook(vm, 'beforeCreate', undefined, false /* setContext */) + + const opts = vm.$options initInjections(vm) // resolve injections before data/props + initProps(vm, opts.props) + initSetup(vm) + callHook(vm, 'beforeCreate', undefined, false /* setContext */) initState(vm) initProvide(vm) // resolve provide after data/props callHook(vm, 'created') diff --git a/src/core/instance/state.ts b/src/core/instance/state.ts index aedb72555..52b23cfd4 100644 --- a/src/core/instance/state.ts +++ b/src/core/instance/state.ts @@ -2,7 +2,6 @@ import config from '../config' import Watcher from '../observer/watcher' import Dep, { pushTarget, popTarget } from '../observer/dep' import { isUpdatingChildComponent } from './lifecycle' -import { initSetup } from 'v3/apiSetup' import { set, @@ -51,11 +50,6 @@ export function proxy(target: Object, sourceKey: string, key: string) { export function initState(vm: Component) { const opts = vm.$options - if (opts.props) initProps(vm, opts.props) - - // Composition API - initSetup(vm) - if (opts.methods) initMethods(vm, opts.methods) if (opts.data) { initData(vm) @@ -69,7 +63,8 @@ export function initState(vm: Component) { } } -function initProps(vm: Component, propsOptions: Object) { +export function initProps(vm: Component, propsOptions: Object | undefined) { + if (!propsOptions) return const propsData = vm.$options.propsData || {} const props = (vm._props = shallowReactive({})) // cache prop keys so that future props updates can iterate using Array diff --git a/test/unit/features/v3/apiSetup.spec.ts b/test/unit/features/v3/apiSetup.spec.ts index 11757878e..21b837694 100644 --- a/test/unit/features/v3/apiSetup.spec.ts +++ b/test/unit/features/v3/apiSetup.spec.ts @@ -263,7 +263,7 @@ describe('api: setup context', () => { }).$mount() expect(spy).toHaveBeenCalled() }) - + // #12561 it('setup props should be reactive', () => { const msg = ref('hi') @@ -333,4 +333,30 @@ describe('api: setup context', () => { await nextTick() expect(_listeners.foo()).toBe(2) }) + + // #12802 + it('should be called before all lifecycle hooks', () => { + const calls: string[] = [] + + Vue.mixin({ + beforeCreate() { + calls.push('global beforeCreate') + } + }) + + new Vue({ + beforeCreate() { + calls.push('component beforeCreate') + }, + setup() { + calls.push('setup') + } + }) + + expect(calls).toEqual([ + 'setup', + 'global beforeCreate', + 'component beforeCreate' + ]) + }) })