前言

函数式组件一般比较简单,没有任何的管理状态,也没有监听任何传递给它的状态,也没有生命周期方法,实际上,它仅仅是接受一些prop的函数,
在这样的场景下,我们可以将组件标记为functional,这意味着它将无状态(没有响应式数据),也没有实例上下文。

函数式组件的定义与使用

官方提供了两种方式来定义函数式组件

函数式组件的定义

1、纯代码方式定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  Vue.component('my-functional-component', {
functional: true,
props: {
// 传递进来的参数
xxx: {
type: Object,
default: null
}
},
render(h, context){
// context为传递进来的上下文
}
});
// 或者我们可以直接是以👇的一个单JS文件来定义,然后再在具体的页面/组件中来使用,个人一般使用以下的方式来创建自己的一个函数式组件
export default {
functional: true,
props: {},
render(h, context){}
}
2、单组件文件定义
1
2
3
4
5
6
<template functional></template>
<script>
export default {
// ...
}
</script>

这里context是函数式组件所需要的所有数据来源,它主要有以下的一个组成部分

函数式组件上下文 Context

函数式组件的使用

因为函数式组件只是一个函数,因此渲染开销也低很多,在作为包装组件时,他们也同样非常有用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  // FunctionList.js
export default {
// ✨ 这里推荐将函数式组件的名字也给维护进去,这样子的话,我们在对应的调试工具就可以通过名字直接找到对应的已定义的函数式组件了,而不会是展示为匿名的组件
name: 'FunctionList',
functional: true,
// 这里是可选的,因为函数式组件是无法访问得到this上下文,并通过this上下文来去到props属性的
// 这里定义的目的是为了让编辑器能够识别到这个函数式组件可以有哪些属性可以直接传递
props: {
itemList: {
type: Array,
default: null
},
header: {
type: String,
default: ''
}
},
render(h, context){
let { itemList, header } = context.props;
return h('div', [
h('div', header),
h('ul', itemList.map(item => {
return h('li', item);
}))
]);
}
}

实际运用场景剖析

  1. 比如一些列表页面、只有纯展示需求的页面,这种情况下它不需要有内部状态,不需要在其内部的生命周期钩子函数中来进行逻辑的编写;
  2. 像这个网站的装修,我觉得应该是可以作为函数式组件的一个使用场景来使用的,比如有一个手机电商网站平台的装修,通过装修每一个楼层的外观+数据集合,将整体的视觉效果给装修出来
    楼层中的每一个元素都是1⃣️函数式组件,因为其仅有纯展示的诉求,而每个楼层均使用自定义的外层函数式组件来包裹起来,外层的函数式组件就是一高阶组件

    个人认为高阶组件,就是通过函数嵌套的方式,包裹普通组件,然后给普通组件追加额外的数据+方法,并控制其孩子组件的渲染逻辑

因此这里的外层函数式组件通过对内部包裹的孩子组件进行额外数据的追加,以及提供的事件的响应处理逻辑,就可以达到对不同类型楼层组件的统一管理,也方便后期进行统一管理,当有新的楼层组件诉求时,
可以直接在原有的地方进行统一的追加,这里,我觉得可以借鉴于之前所学习的工厂模式,针对不同的类型,进行不同的组件楼层的渲染生成,每个楼层各自仅维护自身的一个渲染效果。

与普通插槽组件的对比思考

对比项目 函数式组件 普通插槽组件
性能 直接就是一VNode声明函数,无Vue.compile一说 多了Vue.compile操作
使用场景 纯数据展示,追加额外的属性/动作 通过包裹其他元素,同时具备有对应的声明周期钩子函数
自定义程度 高度自定义,可通过函数的内容拼装实现纯展示复杂组件 同左