This is the seventh day of my participation in the First Challenge 2022. For details: First Challenge 2022.

The biggest difference between Vue3 and Vue2 is the introduction of the Composition API

Composition API experience

<body>
  <div id="app">
    <h1>vue3 composition API</h1>
    <p>{{ counter }}</p>
  </div>
  <script>
    const app = Vue.createApp({
      setup(props, { emit, slots, attrs }) {
        const counter = Vue.ref(0)
        Vue.onMounted(() = > {
          setInterval(() = > {
            counter.value++
          }, 1000)})return {
          counter
        }
      }
    })

    app.mount('#app')
  </script>
</body>
Copy the code

Look at the source code with doubt

  1. When is the Componsition API(Setup) executed?
  2. setupWhy can not usecreatedLife cycle?
  3. The setup parameters passed in are props and CTX, respectively. Where and what are they from?
  • You can explore it step by step, starting with mount, in the previous articleVue3.0 source code learning — initialization process analysis (3. Patch process), understand that the mount process will execute the rendering functionrenderAnd will experiencepatchThe first mount will goprocessComponent= >mountComponentPosition,packages\runtime-core\src\component.ts

  • mountComponentInitializes the component (root component) instance insetupComponent(instance)

Here the instance of the component is already created, so it doesn’t make sense to use beforeCreate and created in setup

  const mountComponent: MountComponentFn = (
    initialVNode, // Root component vnode
    container,
    anchor,
    parentComponent,
    parentSuspense,
    isSVG,
    optimized
  ) = > {
    // 2.x compat may pre-create the component instance before actually
    / / compatible vue2. X
    // mounting
    const compatMountInstance =
      __COMPAT__ && initialVNode.isCompatRoot && initialVNode.component
    
    // 1. Create a component instance, specifically an instance of the root component
    const instance: ComponentInternalInstance =
      compatMountInstance ||
      (initialVNode.component = createComponentInstance(
        initialVNode,
        parentComponent,
        parentSuspense
      ))

    ...

    // resolve props and slots for setup context
    // Handle the setup context
    if(! (__COMPAT__ && compatMountInstance)) {if (__DEV__) {
        startMeasure(instance, `init`)}// Initialize the component instance, equivalent to _init() in vue2 source code
      setupComponent(instance)
      if (__DEV__) {
        endMeasure(instance, `init`)}}... }Copy the code
  • setupComponentWill return asetupResult = setupStatefulComponentIs the user configurationsetupIn the functionreturnThe value of the
export function setupComponent(
  instance: ComponentInternalInstance,
  isSSR = false
) {
  isInSSRComponentSetup = isSSR

  const { props, children } = instance.vnode
  // Whether there are stateful components, non-functional components
  const isStateful = isStatefulComponent(instance)
  // Initialize props and slots
  initProps(instance, props, isStateful, isSSR)
  initSlots(instance, children)

  // If the component is stateful, perform state initialization and return the setup option return value
  const setupResult = isStateful
    ? setupStatefulComponent(instance, isSSR)
    : undefined
  isInSSRComponentSetup = false
  return setupResult
}
Copy the code

  • setupStatefulComponentTo get the componentssetupconfiguration

Setup is performed via callWithErrorHandling and the props and context context are passed in on the instance

function setupStatefulComponent(instance: ComponentInternalInstance, isSSR: boolean) {
  const Component = instance.type as ComponentOptions

  ... 
  // 2. call setup()
  const { setup } = Component
  // If the user sets the setup function
  if (setup) {
    // Create a context object for the setup function
    const setupContext = (instance.setupContext =
      setup.length > 1 ? createSetupContext(instance) : null)
    // Set the instance of the current component to vue.getCurrentInstance
    setCurrentInstance(instance)
    // Pause tracing to improve performance
    pauseTracking()
    Exceptions can be caught by calling setup() with callWithErrorHandling
    const setupResult = callWithErrorHandling(
      setup,
      instance,
      ErrorCodes.SETUP_FUNCTION,
      // Here is the props for setup(), CTX context
      [__DEV__ ? shallowReadonly(instance.props) : instance.props, setupContext]
    )
    resetTracking()
    unsetCurrentInstance()

    if (isPromise(setupResult)) {
      ...
    } else {
      If setup() does not return a Promise, the result handler is executed
      handleSetupResult(instance, setupResult, isSSR)
    }
  } else{... }}Copy the code

You can see the incoming CTX context in step debugging