Usage Scenarios and Source Analysis of Functional Components of Vue Advanced Components

  • 2021-12-04 18:09:19
  • OfStack

Directory introduction Usage scenario Source code analysis Summarize

Introduction

Vue provides a functionalized component that makes the component stateless and instantiless. In principle, all subcomponents go through the process of instantiation, but simple function components do not have this process. It can be simply understood as a middle layer, which only processes data and does not create instances. Because of this behavior, its rendering overhead will be much lower. The actual application scenario is that when we need to choose one of multiple components to render, or process data before transferring data such as children, props and data to sub-components, we can use functional components to complete it, which is essentially an external packaging of components.

Usage scenario

Defines two component objects, test1, test2


var test1 = {
props: ['msg'],
render: function (createElement, context) {
  return createElement('h1', this.msg)
}
}
var test2 = {
props: ['msg'],
render: function (createElement, context) {
  return createElement('h2', this.msg)
}
}

Defines 1 functional component, which will select 1 component for selection according to the calculation result


Vue.component('test3', {
//  Flags for functional components  functional Set to true
functional: true,
props: ['msg'],
render: function (createElement, context) {
  var get = function() {
    return test1
  }
  return createElement(get(), context)
}
})

Use of functional components


<test3 :msg="msg" id="test">
</test3>
new Vue({
el: '#app',
data: {
  msg: 'test'
}
})

The final rendering result is:


<h2>test</h2>

Source code analysis

Functional components set the functional property to true in the object definition of the component, which is the key to distinguish ordinary components from functional components. Similarly, when a subcomponent placeholder is encountered, it will enter createComponent to create a subcomponent Vnode. Because of the functional attribute, the code goes into the branch of the functional component and returns the result of the createFunctionalComponent call. Note that after createFunctionalComponent is executed, the subsequent logic for creating child Vnode will not be executed, which is why there will be no child Vnode to instantiate child components during the process of creating real nodes. (No instances)


function createComponent(){
   ... 
  if (isTrue(Ctor.options.functional)) {
    return createFunctionalComponent(Ctor, propsData, data, context, children)
  }
}

The createFunctionalComponent method detects and merges the incoming data, instantiates FunctionalRenderContext, and finally calls the render method customized by the functional component to perform the rendering process.


function createFunctionalComponent(
  Ctor, //  Functional component constructor 
  propsData, //  Object of the incoming component props
  data, //  Object passed in by the placeholder component attr Attribute 
  context, // vue Instances 
  children//  Child node 
){
  //  Data detection merging 
  var options = Ctor.options;
  var props = {};
  var propOptions = options.props;
  if (isDef(propOptions)) {
    for (var key in propOptions) {
      props[key] = validateProp(key, propOptions, propsData || emptyObject);
    }
  } else {
    //  Merge attrs
    if (isDef(data.attrs)) { mergeProps(props, data.attrs); }
    //  Merge props
    if (isDef(data.props)) { mergeProps(props, data.props); }
  }
  var renderContext = new FunctionalRenderContext(data,props,children,contextVm,Ctor);
  //  Call the custom in the functional component render Function 
  var vnode = options.render.call(null, renderContext._c, renderContext)
}

The ultimate goal of the FunctionalRenderContext class is to define an render method that is different from the real component rendering.


function FunctionalRenderContext() {
  //  Omit other logic 
  this._c = function (a, b, c, d) { return createElement(contextVm, a, b, c, d, needNormalization); };
}

When the render function is executed, the createElement method will be called recursively. At this time, the component is already a real component, and the normal component mounting process begins to be executed.

Question: Why do functional components need to define a different createElement method? -The difference between the functional component createElement and the previous only 1 is that the last parameter is different. As mentioned in the previous chapter, createElement will decide whether to flatten the sub-Vnode according to the last parameter. Under normal circumstances, the compiled results of children are of Vnode type. Only the functional component is special, and it can return an array. At this time, flatten is necessary. Let's look at the following example:


Vue.component('test', {  
  functional: true,  
  render: function (createElement, context) {  
    return context.slots().default  
  }  
}) 

<test> 
     <p>slot1</p> 
     <p>slot</p> 
</test>

At this time, the render function of the functional component test returns Vnode of two slot, which exists in the form of array, which is the scene that needs to be flattened.

Simple summary of 1 functional components, from the source code can be seen that functional components do not have the process of instantiating components like ordinary components, so there is no process including the life cycle of components and the data management of components. It will only receive the data transmitted to components intact and process them, and render the required content. Therefore, as a pure function, the rendering overhead can also be greatly reduced.

Summarize


Related articles: