【译】Vue.js函数式组件,什么是函数式组件?为什么要用?什么时候用?

7,256 阅读4分钟

原文:medium.com/js-dojo/vue…
作者:Austin Gil
翻译:前端小白

TL,DR: 如果你的组件不需要状态,那么将其转换为函数式组件可以将性能提高70%。

什么是函数式组件

函数组件(不要与 Vue 的 render 函数混淆)是一个不包含状态和实例的组件。

简单的说,就是组件不支持响应式,并且不能通过 this 关键字引用自己。

使用 Vue Template 的函数式组件
使用 render 函数的函数式组件

访问组件属性

  • slots: 一个返回 slots 对象的函数

没有状态或实例,你可能会好奇如何引用数据或方法,Vue为底层的 render 函数提供一个 context 参数对象。

这个 context 参数对象具有下列属性:

  • props: 所有的 props 对象
  • children: VNode 子节点数组
  • scopedSlots: (vue2.6.0+) 暴露传入作用域插槽的对象。将普通插槽作为函数暴露出去
  • data: 全部的数据对象,作为 createElement 函数的第二个参数传递给组件
  • parent: 对父组件的引用
  • listeners: (vue2.3.0+) 包含父级注册的事件侦听器的对象。也是 data.on 的别名
  • injections: (v2.3.0+) 如果使用了 inject 选项,则该对象包含了应当被注入的属性

访问这个 context 参数非常简单,例如,我们想使用 props,可以这样做:

在 Template 中访问组件的 context
在 render 函数中访问组件的 context

关于函数式组件和 props 的简要说明

在函数式组件中,实际上不需要注册它接受的 props,但是,如果你注册了它们,仍然会根据它们的配置对它们进行验证。我个人认为注册它们仍然是一个好主意,这样我就可以指定类型、是否必需、默认值或自定义验证器。

为什么函数式组件很棒

函数式组件可能会给我们使用组件带来更多的复杂性,但为什么还是需要呢?

速度

因为函数式组件没有状态,所以它们不需要像Vue的响应式系统一样需要经过额外的初始化。

函数式组件仍然会对相应的变化做出响应式改变,比如新传入新的 props,但是在组件本身中,它无法知道数据何时发生了更改,因为它不维护自己的状态。

对于那些喜欢看数字说话的人,我做了一个基准测试,渲染1000个列表,有状态组件和函数式组件,有状态组件耗时140ms,函数式组件耗时40ms。

参考示例:codesandbox.io/s/vue-templ…

对于大型应用程序,在使用函数式组件之后,你会看到DOM的渲染、更新会有重大改进。

什么时候使用函数式组件

函数式组件可能不适用于许多情况。毕竟,使用 JavaScript 框架的目的是构建响应式的应用程序。在 Vue 中,如果没有响应式,就无法做到这一点。

然而,有些场景就很适合函数式组件的使用:

  • 一个简单的展示组件,也就是所谓的 dumb 组件。例如, buttons, pills, tags, cards,甚至整个页面都是静态文本,比如 About 页面。
  • “高阶组件”——用于接收一个组件作为参数,返回一个被包装过的组件
  • v-for 循环中的每项通常都是很好的候选项

注意

当我在下面这种情况下使用时,就遇到了一个小问题:

使用 <template> 标签,通过 prop 接收数据,有时候我们想在 template 里面修改数据

对于标准的 Vue 组件,使用方法或计算属性都很容易。对于函数式组件,我们无法访问方法或计算属性。

但是,有一种方法可以做到这点:

假设我们的组件接受一个 user prop,它是一个对象,具有firstNamelastName 属性,我们想要渲染一个显示全名的模板

在函数式组件的 <template> 中,我们在组件定义是提供一个方法,然后使用Vue提供的 $options 属性,可以访问这个特殊的方法。

函数式组件中的计算属性

我个人没有遇到过这个问题,是一个社区成员发现的,当嵌套具有作用域插槽的函数式组件,其行为与嵌套具有作用域插槽的有状态组件是不同的,参考链接

结论

如果你关心性能方面,或者正在处理一个大型应用,可以考虑下函数式组件的应用。它的学习曲线很低,而且会为性能带来很大提升。