Ver Fonte

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.
Evan You há 3 anos atrás
pai
commit
e1342df784

+ 7 - 2
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')

+ 2 - 7
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

+ 27 - 1
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'
+    ])
+  })
 })