6.2 函数式组件

Vue提供了一种就可以让组件变为无状态、无实例的函数化组件,既然这个组件是函数,那么它的渲染开销会低很多。一搬情况下,当我们需要在多个组件中选择一个来代为渲染,或者在将children,props,data等数据传递给子组件前进行数据处理,我们都可以用函数式组件来完成,其本质上也是对组件的一个外部包装。

6.2.1 使用场景

    • 定义两个组件对象,test1,test2
  1. var test1 = {
  2. props: ['msg'],
  3. render: function (createElement, context) {
  4. return createElement('h1', this.msg)
  5. }
  6. }
  7. var test2 = {
  8. props: ['msg'],
  9. render: function (createElement, context) {
  10. return createElement('h2', this.msg)
  11. }
  12. }
  • 2.定义函数式组件
  1. Vue.component('test3', {
  2. // 函数式组件的标志 functional设置为true
  3. functional: true,
  4. props: ['msg'],
  5. render: function (createElement, context) {
  6. var get = function() {
  7. return test1
  8. }
  9. return createElement(get(), context)
  10. }
  11. })
  • 3.使用函数式组件
  1. <test3 :msg="msg" id="test">
  2. </test3>
  3. new Vue({
  4. el: '#app',
  5. data: {
  6. msg: 'test'
  7. }
  8. })

最终渲染的结果为:

  1. <h2>test</h2>

6.2.2 源码分析

函数式组件会在组件的对象定义中,将functional属性设置为true,在根实例挂载的过程中,遇到函数式组件的占位符依然会进入创建子组件createComponent的流程。由于functional属性的存在,代码会进入函数式组件的分支中,并返回createFunctionalComponent调用的结果。

  1. function createComponent(){
  2. ···
  3. if (isTrue(Ctor.options.functional)) {
  4. return createFunctionalComponent(Ctor, propsData, data, context, children)
  5. }
  6. }

createFunctionalComponent方法会对传入的数据进行检测和合并,实例化FunctionalRenderContext,最终调用函数式组件自定义的render方法执行渲染过程。

  1. function createFunctionalComponent(
  2. Ctor, // 函数式组件构造器
  3. propsData, // 传入组件的props
  4. data, // 占位符组件传入的attr属性
  5. context, // vue实例
  6. children// 子节点
  7. ){
  8. // 数据检测合并
  9. ...
  10. // 实例化
  11. var renderContext = new FunctionalRenderContext(data,props,children,contextVm,Ctor);
  12. // 执行render函数
  13. var vnode = options.render.call(null, renderContext._c, renderContext)
  14. }

Function这个类最终的目的是定义一个和真实组件渲染不同的render方法。

  1. function FunctionalRenderContext() {
  2. // 省略其他逻辑
  3. this._c = function (a, b, c, d) { return createElement(contextVm, a, b, c, d, needNormalization); };
  4. }

执行render函数的过程,又会递归调用createElement的方法,这时的组件已经是真实的组件,开始执行正常的组件挂载流程。

从源码中可以看出,函数式组件并不会像普通组件那样有挂载组件周期钩子,监听状态和管理数据的过程,它只会原封不动的接收传递给组件的数据做处理。因此作为纯粹的函数它只做数据的处理以及渲染组件的选择,这也大大降低了函数式组件的开销。