According to this response type principle to write a source code principle. Ps: can water several, the needle does not stamp

Data difference between Vue 3.X and Vue 2.X

Props, data, etc

Vue 2.x

Inject 1, find provid by iterating parent level from itself, Inject while (source) {if (source._provided && hasOwn(source._provided, ProvideKey) {result[key] = source._provided[provideKey] break} source = source.$parent} Add to props 1, traverse props, and vm for (const key in propsOptions) {if (! (key in VM)) {proxy(vm, '_props', key)}} methods 1, when methods is a function, change this to vm. Vm [key] = typeof Methods [key]! == 'function' ? Noop: bind(methods[key], VM) non-production environment: methods[key] is not available on functions, props, key starts with _ or $ $options.data data = vm._data = typeof data === 'function'? GetData (data, vm) : data | | {} 2, access to the key value of the data object. Additions to the VM (instance) that already exist in the PROPS cannot be added to the VM (instance) in a non-production environment: Error message for methods[key] Keys (data) let I = keys.length while (I --) {const key = keys[I] if (props &&) hasOwn(props, key)) { ... } else if (! IsReserved (key)) {proxy(VM, '_data', key)}} computed If a key element exists on a VM, an error occurs in data, props, and methods. Otherwise add it to the VM (instance) if (! (key in vm)) { defineComputed(vm, key, userDef) } else if (process.env.NODE_ENV ! == 'production') { if (key in vm.$data) { warn(`The computed property "${key}" is already defined in data.`, vm) } else if (vm.$options.props && key in vm.$options.props) { warn(`The computed property "${key}" is already defined as a prop.`, vm) } else if (vm.$options.methods && key in vm.$options.methods) { warn(`The computed property "${key}" is already defined as a method.`, vm) } }Copy the code

You can see the options order of Vue 2.x

  • inject
  • Props: Added when the VM (instance) does not exist
  • Methods: Directly overwrites the elements of inject and props on the VM (instance)
  • An element with the same name already exists on data: props cannot be added to a VM (instance)
  • Computed: Added if it does not exist on the VM (instance)

Execute between beforeCreate and created

Vue 3.x

Setup is added, and execution before beforeCreate also gets props and slots.

const mountComponent = (initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, Optimized) => {// createComponentInstance const instance = (initialVNode.component = createComponentInstance(initialVNode, ParentComponent, parentSuspense) // setupComponent(instance) // Set and run the render function setupRenderEffect(instance, initialVNode, container, anchor, parentSuspense, isSVG, optimized) }Copy the code

CreateComponentInstance Initializes a component instance

Initializes the component instance const instance: ComponentInternalInstance = {uid: uid++ vnode, type, parent, propsOptions: normalizePropsOptions(type, appContext), emitsOptions: normalizeEmitsOptions(type, appContext), // emit emit: null as any, // to be set immediately emitted: null, // state ctx: EMPTY_OBJ, data: EMPTY_OBJ, props: EMPTY_OBJ, attrs: EMPTY_OBJ, slots: EMPTY_OBJ, refs: EMPTY_OBJ, setupState: EMPTY_OBJ, setupContext: null, // lifecycle isMounted: false, isUnmounted: false, isDeactivated: false, bc: null, c: null, bm: null, m: null, bu: null, u: null, um: null, bum: null, da: null, a: null, rtg: null, rtc: null, ec: null ... } instance.root = parent ? parent.root : instance instance.emit = emit.bind(null, instance) return instanceCopy the code

setupComponent

The setup process for the component instance, the setup function, is done here

Setup execution has two parameters,setup(props,{attrs,slots,emit}), which are processed before setup execution in order to be accessible

const { props, Children} = instance.vnode const isStateful = isStatefulComponent(instance) Initialized Props/initProps(instance, Props, IsStateful (isSSR) initSlots(instance, children) initSlots(instance, children) container setupResult = isStateful? setupStatefulComponent(instance, isSSR) : Undefined isInSSRComponentSetup = false return The emit parameter in setupResult setup is done when creating the component instance InitProps, initSlots, and setupStatefulComponentCopy the code

initProps

const [options, NeedCastKeys] = instance.propsOptions if (props) {for (const key in props) {const value = props[key] // In the options of propsOptions is the props property, Let camelKey if (options && hasOwn(options, (camelKey = camelize(key)))) { props[camelKey] = value } else if (! IsEmitListener (instance.emitsOptions, key) {attrs[key] = value}}} Setup parameters attrs and props are completeCopy the code

initSlots

instance.slots = children
Copy the code

setupStatefulComponent

AccessCache = object.create (null) Creates the context CTX proxy, Page rendering property access and after this visit is the proxy instance. The proxy = new proxy (instance. CTX PublicInstanceProxyHandlers)Copy the code
PublicInstanceProxyHandlers
const { ctx, setupState, data, props, accessCache, type, appContext } = instance if (key[0] ! == '$') { const n = accessCache! [key] if (n ! == undefined) { switch (n) { case AccessTypes.SETUP: return setupState[key] case AccessTypes.DATA: return data[key] case AccessTypes.CONTEXT: return ctx[key] case AccessTypes.PROPS: return props! [key] } } else if (setupState ! == EMPTY_OBJ && hasOwn(setupState, key)) { accessCache! [key] = AccessTypes.SETUP return setupState[key] } else if (data ! == EMPTY_OBJ && hasOwn(data, key)) { accessCache! [key] = AccessTypes.DATA return data[key] } else if ( (normalizedProps = instance.propsOptions[0]) && hasOwn(normalizedProps, key) ) { accessCache! [key] = AccessTypes.PROPS return props! [key] } else if (ctx ! == EMPTY_OBJ && hasOwn(ctx, key)) { accessCache! [key] = AccessTypes.CONTEXT return ctx[key] } else if (! __FEATURE_OPTIONS_API__ || ! isInBeforeCreate) { accessCache! [key] = AccessTypes.OTHER } }Copy the code

The sequence is setupState, data, props, and CTX. HasOwn is required for each query, so the setupState, data, props, and CTX positions of the accessCache record variables are added to access the data of the corresponding element. (An optimization point)

Set is in the same order as setupState, data, props, CTX, and so on

As you can see, the order is setupState, data, props, CTX. Since the variables under each element are accessed rather than being added to the CTX instance, there is no overwriting problem

import { ref } from 'vue' export default { data() { return { msg: 'msg from data' } }, setup() { const msg = ref('msg from setup') return { msg } }, methods: {random() {this.msg = math.random ()}}} will display the setup.msg variable, and this.msg will modify the variable in MSGCopy the code

Finally, take a look at the setup execution

Const {setup} = Component Setup Whether to use the parameter const setupContext = (instance.setupContext = setup.length > 1? createSetupContext(instance) : null) currentInstance = instance const setupResult = callWithErrorHandling( setup, instance, ErrorCodes.SETUP_FUNCTION, [__DEV__ ? shallowReadonly(instance.props) : instance.props, setupContext] ) handleSetupResult(instance, setupResult, isSSR)Copy the code
createSetupContext
    {
      attrs: instance.attrs,
      slots: instance.slots,
      emit: instance.emit,
    }
Copy the code
callWithErrorHandling
let res try { res = args ? fn(... args) : fn() } catch (err) { handleError(err, instance, type) } return resCopy the code

handleSetupResult

If (isFunction(setupResult)) {// setup returns the render function instance.render = setupResult} else if (isObject(setupResult)) SetupState = reactive(setupResult)}Copy the code
Vue 2.x Vue 3.x
Inject, props, methods, data, and computed are written to vm instances, where variable names cannot be repeated SetupState, data, props, and CTX in their corresponding elements, variable names can be repeated
Inject, props, methods, data, and computed are uniformly initialized in beforeCreate to Created SetupState, data, props, Slot, and CTX are initialized before setup is executed
Variable names must be unique Variable names can be repeated, but pay attention to the priority of access