函数式组件是无状态的组件,就像纯函数一样。他接收 props ,返回虚拟 dom 。
函数式组件无须初始化 data 以及生命周期钩子,也没有 this ,函数式组件的初始化性能消耗小于有状态组件。
组合式 API 中也没有
this
下面定义了一个名为 DemoChild 的函数式组件
<script src="../../dist/vue.global.js"></script>
<script>
function DemoChild(props) {
console.log('DemoChild == ', this) // 此处的 this 为 Window
return Vue.h('h1', props.msg)
}
</script>
h函数用于创建虚拟 DOM 节点(vnode)。具体可见 渲染函数 API | Vue.js
其实,函数式组件最大的优势不是性能,而是他的简单性。因为在 Vue3 中,即使是有状态组件,其初始化性能消耗也非常小。由于函数式组件的简单性,使其比有状态组件更加适合仅需数据展示,而没有任何交互的场景。
函数式组件本质上是一个函数,在 Vue 的源码中,函数式组件的实现逻辑复用了有状态组件的实现逻辑。只是在实现函数式组件的时候,会先判断是否为函数式组件,有选择性地复用有状态组件的实现逻辑。
从这点也可以看出,Vue 源码的代码复用性还是挺高的,不会说在实现了有状态组件后,为了实现函数式组件需要重新定义其他函数来实现函数式组件。
// packages/runtime-core/src/component.ts
// 判断是否为有状态组件
export function isStatefulComponent(instance: ComponentInternalInstance) {
return instance.vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT
}
本文中的源码均摘自 Vue.js 3.2.45,为了方便理解,会省略与本文主题无关的代码
// packages/runtime-core/src/component.ts
// 初始化 props 和插槽,获取 setup 钩子的返回值
export function setupComponent(
instance: ComponentInternalInstance,
isSSR = false
) {
isInSSRComponentSetup = isSSR
const { props, children } = instance.vnode
const isStateful = isStatefulComponent(instance)
initProps(instance, props, isStateful, isSSR)
initSlots(instance, children)
// 对于函数式组件来说,setup 钩子的返回值是 undefined
const setupResult = isStateful
? setupStatefulComponent(instance, isSSR)
: undefined
isInSSRComponentSetup = false
return setupResult
}
总结
函数式组件本质是函数,在 Vue 源码中,函数式组件的实现逻辑复用了有状态组件的实现逻辑。
函数式组件的特点是无状态,没有生命周期,也没有 this 。这使得函数是组件的初始化性能消耗低于有状态组件,但是函数式组件最大的优势并不是他的性能,而是他的简单性,因为在 Vue3 中,有状态组件的初始化性能消耗也非常小。而函数式组件的简单性,使其非常适合仅需数据展示,而没有任何交互的场景。
参考
《Vue.js 设计与实现》霍春阳·著