函数式组件是什么?
官方解释:使组件无状态 (没有 data) 和无实例 (没有 this 上下文)。他们用一个简单的 render 函数返回虚拟节点使它们渲染的代价更小。 简单来说就是,以javaScript函数来定义组件的渲染函数,函数式组件没有模板、组件没有状态(data,存储数据的能力,类似react的无状态组件)、生命周期,它们非常轻量级,并且易于创建和使用。常用于组装复杂页面或组件(深层次组件颗粒化,使用的较好方案之一)。
使用场景
初步使用 函数式组件
<template>
<div class="VNode">
<VNode :age='30' @up="up"/>
</div>
</template>
<script>
export default {
name: "App",
components: {
VNode: {
functional: true,
render(h,ctx) {
console.log(ctx)
return h("div", {
on:{
click:()=>ctx.data.on.up(ctx.props.age+'老了')
}
}, ctx.props.age);
},
},
},
data() {
return {};
},
methods:{
up(value){
console.log('父组件接收子组件的值', value);
}
}
};
</script>
场景1:
全局很多地方需要具备“根据传入的年龄去查询是否需要养老”的组件A:
全局很多地方需要具备“根据传入的身份证号判断是否当前用户是否已缴纳养老保险,未缴纳做出提示”的组件B:
home.vue:
<template>
<div class="HomeIndex">
<!-- 传入年龄判断是否需要养老 -->
<VNode :age="29" :render="ageRender" />
<!-- 传入身份证号码计算建议缴纳年限,和建议缴纳地等 -->
<VNode iDCard="3623211" :render="idRender" />
</div>
</template>
<script>
import { ageRender, idRender } from "./component";
export default {
name: "HomeIndex",
components: {
VNode: {
functional: true,
render(h, ctx) {
console.log(ctx);
return ctx.props.render(h, ctx);
},
},
},
data() {
return {
ageRender,
idRender,
};
},
};
</script>
component.js
/**
* 我是一个创建 标签的函数,我支持很多不同样式的标签
*/
export function creatLabelValue(h, { label, value }) {
return h("div", {}, [h("span", {}, label + ":"), h("span", {}, value)]);
}
/**
* 我是一个很花哨的组件 我是组件 A
*/
export function ageRender(h, ctx) {
const age = ctx.props.age;
const masg = +age > 65 ? "需要养老" : "不需要养老";
return h("div", {}, creatLabelValue(h,{label:age,vlaue:masg}));
}
/**
* 我是一个功能很多的组件 我是组件 B
*/
export function idRender(h, ctx) {
const iDCard = ctx.props.iDCard;
/** 经过一系列的复杂判断规则得出结果 */
return h("div", {}, [
creatLabelValue(h, { label: "身份证", value: iDCard }),
creatLabelValue(h, { label: "年龄", value: "28" }),
creatLabelValue(h, { label: "性别", value: "男" }),
creatLabelValue(h, { label: "建议缴纳年限", value: "30年" }),
creatLabelValue(h, { label: "距退休还剩", value: "37年" }),
]);
}
场景2:
使用jsx,完成上面的案例: HomeJsx.jsx
import { ageRender, idRender } from "./componentJsx";
export default {
name:"HomeJsx",
render(){
return <div class="HomeJsx">
{ageRender(29)}
{idRender('3623211')}
</div>
}
}
componentJsx.jsx
/**
* 我是一个创建 标签的函数,我支持很多不同样式的标签
*/
export function creatLabelValue({ label, value }) {
// return h("div", {}, [h("span", {}, label + ":"), h("span", {}, value)]);
return (
<div>
<span>{label}</span>
<span>{value}</span>
</div>
);
}
/**
* 我是一个很花哨的组件 我是组件 A
*/
export function ageRender(age) {
const masg = +age > 65 ? "需要养老" : "不需要养老";
// return h("div", {}, creatLabelValue(h, { label: age, vlaue: masg }));
return creatLabelValue({ label: age, vlaue: masg });
}
/**
* 我是一个功能很多的组件 我是组件 B
*/
export function idRender(iDCard) {
/** 经过一系列的复杂判断规则得出结果 */
// return h("div", {}, [
// creatLabelValue(h, { label: "身份证", value: iDCard }),
// creatLabelValue(h, { label: "年龄", value: "28" }),
// creatLabelValue(h, { label: "性别", value: "男" }),
// creatLabelValue(h, { label: "建议缴纳年限", value: "30年" }),
// creatLabelValue(h, { label: "距退休还剩", value: "37年" }),
// ]);
return (
<div>
{[
creatLabelValue({ label: "身份证", value: iDCard }),
creatLabelValue({ label: "年龄", value: "28" }),
creatLabelValue({ label: "性别", value: "男" }),
creatLabelValue({ label: "建议缴纳年限", value: "30年" }),
creatLabelValue({ label: "距退休还剩", value: "37年" }),
]}
</div>
);
}
ps:像 componentJsx.jsx 直接这样写会报错。需要下载依赖 "@vue/babel-preset-jsx" 并在babel.config.js 加入
module.exports = {
presets: [
[
"@vue/babel-preset-jsx",
{
vModel: false,
compositionAPI: true,
},
],
],
};
总结:
正常定义组件,对于大型项目或颗粒化做的比较好的项目而言其实是很损耗性能的。每个.vue组件都需要通过一系列复杂的运算后得出。而函数式组件渲染代价极小,它仅仅只是返回了渲染逻辑的一个方法而已。对于复杂项目,深度颗粒化都比较友善。使用jsx语法,写函数式组件极其方便,故而大型项目使用jsx会比较好。