The creation process of component instances
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 nameprops
: The received props datachildren
: An array of child nodesshapeFlag
: 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 identifiervnode
: The associated virtual nodetype
: The component optionsprops
: A reactive props objectattrs
: Non-props attributesslots
: Slot contentemit
: 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:
- Creating an execution context
- Handling reactive conversion of props and attrs
- Exposing utility methods like
emit
andslots
- 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 initializedcreated
: State initialization is completebeforeMount
: Before the render function is executed for the first timemounted
: 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:
- Render placeholder content first
- Load the actual component code
- Display different interfaces based on the loading state
- 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:
- Coexistence of Options API and Composition API
- More fine-grained reactive tracking
- More aggressive compile-time optimizations
- Lifecycle adjustments for the
setup
function - 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
上一篇:组件定义的内部表示
下一篇:Props的解析与验证