聊聊 Vue2 中的 functional 组件

前言

最近组内有一个分享提到了 Vue2 的 functional 组件,大致上是说这个东西没有生命周期,在渲染层面上,会减少很多的消耗,一番处理之后,首屏时间和内存都能减少不少。

由此,我打算来好好学一下挖一下这个知识点。

functional 组件是什么?

Vue.js 中的 functional 函数化组件是一种特殊类型的无状态组件,它不依赖于内部状态,只依赖于传入的 props。这种组件没有实例,也就是说它们没有 this 上下文。函数化组件的主要特点如下:

  1. 无状态:函数化组件不包含响应式数据或内部状态,它们只依赖于传入的 props。
  2. 无实例:函数化组件没有实例,因此没有 this 上下文。
  3. 更高的性能:由于没有实例和响应式数据,函数化组件的渲染性能更高,适用于频繁更新的场景。
  4. 简洁的定义:函数化组件使用 render 函数定义,不需要完整的 Vue 组件选项对象。

函数化组件的定义示例:

ts 复制代码
Vue.component('my-functional-component', {
  functional: true,
  props: {
    message: {
      type: String,
      required: true
    }
  },
  render: function (createElement, context) {
    return createElement('div', context.props.message);
  }
});

functional函数化组件做比对是深度比对,会对对象深入的做对比,不是浅比较:

如果 props 对象外部不变,但内部的参数发生变化,函数化组件会重新渲染。因为函数化组件是无状态的,它们只依赖于传入的 props。当 props 的内部参数发生变化时,Vue 会检测到这些变化并重新渲染函数化组件。

ts 复制代码
Vue.component('my-functional-component', {
  functional: true,
  props: {
    userInfo: {
      type: Object,
      required: true
    }
  },
  render: function (createElement, context) {
    return createElement('div', context.props.userInfo.name);
  }
});

特点

1.functional 函数化组件本身无 watch/computed ,这就导致我们不能像在普通 Vue 组件中那样使用 watchcomputed 属性来监听参数变化。因为函数化组件没有实例和响应式数据,它们只依赖于传入的 props。当 props 发生变化时,函数化组件会自动重新渲染。

如果我们想要监听怎么办?

比较可行的办法是:在父组件中监听 props 变化,并在适当的时机传递新的 props 给函数化组件。这样,函数化组件会在接收到新的 props 时自动重新渲染。

2.functional 函数化组件本身无实例,这会导致如下后果:

  • 在函数化组件中,无法使用 this 访问组件实例,因为它们没有实例。
  • 由于没有实例,函数化组件无法使用 Vue 实例的方法和属性,例如 $emit$watch$refs 等。
  • 函数化组件没有实例,因此无法使用生命周期钩子函数,如 createdmountedupdated 等。
  • 函数化组件没有响应式数据和内部状态,它们只依赖于传入的 props。这意味着我们无法在函数化组件中使用 datacomputedwatch 等选项。
  • 在函数化组件中,我们需要通过 context 对象访问插槽(slots)和作用域插槽(scoped slots),而不是使用 this.$slotsthis.$scopedSlots

使用如下:

ts 复制代码
Vue.component('my-functional-component', {
  functional: true,
  props: {
    message: {
      type: String,
      required: true
    }
  },
  render: function (createElement, context) {
    // 访问 props
    const message = context.props.message;
    // 访问插槽
    const slots = context.slots();
    const defaultSlot = slots.default;
    // 访问作用域插槽
    const scopedSlots = context.scopedSlots;
    const customSlot = scopedSlots.customSlot;
    // 访问事件监听器
    const listeners = context.listeners;
    const clickListener = listeners.click;
});
相关推荐
半岛@少年10 分钟前
Webpack在前端项目中究竟发挥什么作用?
前端·webpack·前端工程化
2501_9400417411 分钟前
企业官网与品牌落地页,能直接交付的前端题目
前端
川冰ICE12 分钟前
JavaScript高级④|类(class)与面向对象,ES6现代写法
开发语言·javascript·es6
小番茄夫斯基18 分钟前
全球大模型的价格和能力排行汇总
前端·后端·架构
Sirius Wu19 分钟前
Agent模型冷启动问题
开发语言·javascript·人工智能·机器学习·ecmascript·aigc
小小小小宇31 分钟前
前端领域 30 个值得安装的 Agent Skills
前端
xkxnq34 分钟前
第八阶段:工程化、质量管控与高级拓展(132天),Vue项目文档自动化:VuePress搭建组件文档(组件示例+API说明)
javascript·vue.js·自动化
喵了几个咪35 分钟前
基于 Next.js 的 Headless CMS 前端架构:技术解析与二次开发导引
前端·javascript·架构
星栈36 分钟前
Makepad 不只是画界面:事件、状态和组件通信,到底怎么写
前端·rust
dsyyyyy110138 分钟前
只用HTML和CSS实现换一换效果
前端·css·html