阿里云主机折上折
  • 微信号
Current Site:Index > The creation process of component instances

The creation process of component instances

Author:Chuan Chen 阅读数:30657人阅读 分类: Vue.js

The Process of Component Instance Creation

In Vue 3, the creation of a component instance begins when the component is mounted or dynamically rendered. The entire process involves multiple core steps, from the conversion of the virtual DOM to the real DOM, to the triggering of the instance's lifecycle.

Creating a Virtual Node

When a component is parsed, a virtual node is first created via createVNode. This function takes parameters such as the component definition, props, and children, and returns a virtual node object describing the component's structure.

const vnode = createVNode(
  MyComponent,
  { title: 'Example' },
  [createVNode('span', null, 'Child content')]
)

The virtual node contains key information:

  • type: The component options object or DOM tag name
  • props: The received props data
  • children: An array of child nodes
  • shapeFlag: A node type identifier

Instantiating the Component

When the virtual node needs to be mounted, the setupComponent process is triggered:

function setupComponent(instance) {
  // Initialize props
  initProps(instance, instance.vnode.props)
  
  // Initialize slots
  initSlots(instance, instance.vnode.children)
  
  // Execute the setup function
  const setupResult = setupComponent(instance)
  
  // Handle the setup result
  handleSetupResult(instance, setupResult)
}

During instantiation, a component instance object is created, containing core properties:

  • uid: A unique identifier
  • vnode: The associated virtual node
  • type: The component options
  • props: A reactive props object
  • attrs: Non-props attributes
  • slots: Slot content
  • emit: An event emitter

Handling the Setup Function

For components using the Composition API, the setup function is prioritized:

const Comp = {
  setup(props, { attrs, slots, emit }) {
    const count = ref(0)
    return { count }
  }
}

The setup execution phase involves:

  1. Creating an execution context
  2. Handling reactive conversion of props and attrs
  3. Exposing utility methods like emit and slots
  4. Returning the composition state

Template Compilation and Render Function

For template-based components, a compilation phase generates the render function:

// Original template
const template = `<div>{{ count }}</div>`

// Compiled result
const render = () => {
  return h('div', ctx.count)
}

The compilation process includes:

  • Parsing the template into an AST
  • AST transformation and optimization
  • Code generation
  • Generating a scoped render function

Reactive System Binding

During instance creation, reactive associations are established:

function setupRenderEffect(instance) {
  instance.update = effect(() => {
    if (!instance.isMounted) {
      // Initial render
      const subTree = instance.render()
      patch(null, subTree)
      instance.isMounted = true
    } else {
      // Update
      const nextTree = instance.render()
      patch(prevTree, nextTree)
    }
  })
}

This effect will:

  • Track dependencies during rendering
  • Trigger re-rendering when dependencies change
  • Optimize update timing via a scheduler

Lifecycle Hook Invocation

During instantiation, lifecycle hooks are triggered in order:

// Creation phase
callHook(instance, 'beforeCreate')
initState(instance)
callHook(instance, 'created')

// Mounting phase
callHook(instance, 'beforeMount')
setupRenderEffect(instance)
callHook(instance, 'mounted')

Each hook corresponds to a specific instance state:

  • beforeCreate: The instance has just been created, and state is not initialized
  • created: State initialization is complete
  • beforeMount: Before the render function is executed for the first time
  • mounted: The DOM has been mounted

Recursive Handling of Child Components

Parent component instantiation recursively processes child components:

const processComponent = (n1, n2) => {
  if (n1 == null) {
    mountComponent(n2)
  } else {
    updateComponent(n1, n2)
  }
}

const mountComponent = (vnode) => {
  const instance = createComponentInstance(vnode)
  setupComponent(instance)
  setupRenderEffect(instance)
}

This process ensures:

  • The component tree is initialized correctly from top to bottom
  • Props and event systems are properly established
  • Slot content is correctly passed

Handling Asynchronous Components

Special handling is applied for asynchronous components:

defineAsyncComponent({
  loader: () => import('./AsyncComp.vue'),
  loadingComponent: LoadingComp,
  errorComponent: ErrorComp,
  delay: 200,
  timeout: 3000
})

Asynchronous components will:

  1. Render placeholder content first
  2. Load the actual component code
  3. Display different interfaces based on the loading state
  4. Finally replace with the actual component

Handling Higher-Order Components

Additional wrapping is performed for higher-order components:

function withLogging(WrappedComponent) {
  return {
    mounted() {
      console.log('Component mounted')
    },
    render() {
      return h(WrappedComponent, this.$props)
    }
  }
}

Handling features:

  • Preserve the original component's functionality
  • Add extra logic
  • Correctly handle props and event forwarding

Error Handling Mechanism

The instantiation process includes error capturing:

function callWithErrorHandling(fn, instance, type, args) {
  try {
    return args ? fn(...args) : fn()
  } catch (err) {
    handleError(err, instance, type)
  }
}

Error handling includes:

  • Lifecycle hook errors
  • Event handler errors
  • Render function errors
  • Asynchronous error capturing

Performance Optimization Strategies

The instance creation process includes multiple optimizations:

// Static hoisting during compilation
const _hoisted = createVNode('div', null, 'Static content')

// Caching event handlers
const _cache = {}
function render() {
  return h('div', {
    onClick: _cache[1] || (_cache[1] = e => handler(e))
  })
}

Optimization techniques involve:

  • Static node hoisting
  • Event caching
  • Inline function constant extraction
  • Compile-time marking of dynamic nodes

Differences from Vue 2

Vue 3's instance creation process has several improvements:

  1. Coexistence of Options API and Composition API
  2. More fine-grained reactive tracking
  3. More aggressive compile-time optimizations
  4. Lifecycle adjustments for the setup function
  5. Better TypeScript integration
// Vue 2 Options API
export default {
  data() {
    return { count: 0 }
  }
}

// Vue 3 Composition API
export default {
  setup() {
    const count = ref(0)
    return { count }
  }
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.