函数式组件通过跳过实例化、不追踪响应式依赖、不运行生命周期钩子实现最小开销;仅适用于纯渲染场景,输入由props决定、不读写响应式数据、不处理事件;Vue 3推荐直接导出h函数写法,配合上下文参数避免冗余封装;典型场景包括长列表项、布局包装器及原子UI元素。

函数式组件(Functional Component)能直接跳过组件实例化过程,不创建 this、不追踪响应式依赖、不运行生命周期钩子——这本身就是削减开销最彻底的方式。
明确适用边界:只用于无状态展示
函数式组件不是“更高级的组件”,而是“更窄职责的组件”。它只适合纯渲染场景:
- 输入完全由
props决定,输出完全由render函数返回 - 不读取或修改任何响应式数据(包括
ref、reactive、computed) - 不监听事件(
@click等需交由父组件处理),也不触发自定义事件(emit不可用) - 不使用
setup、data、methods、watch等任何有状态能力
三种写法中选最轻量的一种
不同写法带来的开销略有差异,优先级从低到高:
-
单文件组件(SFC)+
<template functional></template>:语法简洁,但编译器仍需解析模板并生成渲染函数,略多一层转换 -
选项式 API +
functional: true:明确标记,逻辑集中,Vue 2/3 兼容性好 - 组合式 API 直接导出函数(Vue 3):零配置、零对象包装,本质就是 JS 函数,开销最小
例如 Vue 3 中推荐写法:
import { h } from 'vue'<br>export default (props, { slots, attrs }) => {<br> return h('span', attrs, slots.default?.())<br>}<br>export.default.props = ['label']
配合上下文参数,避免冗余封装
函数式组件的第二个参数 context(Vue 2)或解构对象(Vue 3)已包含全部必要信息,无需额外提取或转发:
- 用
context.attrs直接透传原生属性,不用再写v-bind="$attrs" - 用
context.slots.default()或slots.default?.()渲染默认插槽,不经过v-slot编译流程 - 用
context.props或解构后的props访问属性,不触发响应式代理访问开销
典型落地场景:列表项与包装器
这些地方最容易堆积大量低价值实例,改用函数式组件收益最明显:
-
长列表中的每一项:如
<user-item :user="u" v-for="u in users" :key="u.id"></user-item>,将UserItem改为函数式,可减少约 40% 渲染开销 -
仅加样式或布局的包装组件:如
<card><h2>标题</h2> <p>内容</p></card>,本身不管理状态,纯靠 class 和 slot 实现 -
图标、标签、徽章等原子级 UI 元素:输入是 icon 名、颜色、尺寸,输出是内联 SVG 或
<span></span>,无副作用

















