Vue 函数式组件的特点与适用场景

432 阅读2分钟

函数式组件是无状态的组件,就像纯函数一样。他接收 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 设计与实现》霍春阳·著