From e1342df7847a51c75192fec74e94378178e046b0 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 11 Oct 2022 16:23:08 +0800 Subject: [PATCH] fix(setup): setup hook should be called before beforeCreate fix #12802 Note this commit moves the initialization of injections and props to before the invocation of beforeCreate. This should not cause breakage because props and inject normalization has always been done before beforeCreate, so code that attempts to modifiy props/inject options inside beforeCreate should have never worked. --- src/core/instance/init.ts | 9 +++++++-- src/core/instance/state.ts | 9 ++------- test/unit/features/v3/apiSetup.spec.ts | 28 +++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 10 deletions(-) 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' + ]) + }) })