我个人理解因为没了状态(data),少了很多响应式的处理,还有生命周期等过程会提高速度和减少内存占用吧?
函数式组件也可以在模板格式中用只需要这样
<template functional> </template>
那jsx中的函数式组件呢?也很简单只需增加配置functional: true就可以了
那函数式组件没有了this 实例怎么绑定事件怎么获取props呢?
组件需要的一切都是通过上下文传递,包括:
props : 提供所有 prop 的对象
children: VNode 子节点的数组
slots: 返回所有插槽的对象的函数
data:传递给组件的数据对象,并将这个组件作为第二个参数传入 createElement
上面我只列举了部分属性,这些是非函数式组件的东西,对于函数式组件
vue 增加了context对象,需要作为render(h,context) 第二个参数传入,this.$slots.default更新为context.children props原本是直接挂在this上的,现在变为context.props挂在了context.props上。this.data变为了context.data
需要注意的是对于函数式组件,没有被定义为prop的特性不会自动添加到组件的根元素上,意思就是需要我们手动添加到组件根元素了,看个例子吧
//父组件 ...省略无关代码 render(){ return ( <Item data={this.data}/> ) } //Item.vue组件 export default { functional:true, name: "item", render(h,context){ return ( <div > {context.props.data} </div> ) } }
上面代码期待的是.large类名传入到了Item的根元素上,但是其实没有。我们需要增加点东西
// Item.vue export default { functional:true, name: "item", render(h,context){ return ( <div {...context.data}> {context.props.data} </div> ) } }
注意到,通过展开运算符把所有的属性添加到了根元素上,这个context.data就是你在父组件给子组件增加的属性,他会跟你在子元素根元素的属性智能合并,现在.large类名就传进来了。这个很有用,当你在父组件给子组件绑定事件时就需要这个了。下面说一个关于绑定事件的小坑
向 createElement 通过传入 context.data 作为第二个参数,我们就把 my-functional-button 上面所有的特性和事件监听器都传递下去了。事实上这是非常透明的,那些事件甚至并不要求 .native 修饰符
上面是vue官网的一段话,然而我看了一遍就忽略了一句很重要的话,就是最后一句,他说不需要.native修饰符了?好先看代码
// 父组件 methods:{ show(){ alert('你好') } }, render(){ return ( <Item data={this.data} onNativeClick={this.show}/> ) }
上面代码乍一看没毛病,自定义组件用onNativeClick嘛,结果就是不会弹窗。唉,最后读了几遍刚才vue文档中的解释,才发现原来函数式组件不需要.native修饰符,对于template格式肯定一下就反应过来了,但是jsx的话,好吧,把上面的onNativeClick重新改为onClick就好了。
现有项目哪些功能可以用jsx代替呢?
这个其实跟最开始我例举的例子很像。我在项目中用它来干掉了满屏的v-if/v-else
由于我的业务是pad上的,需求是一套试卷有几十道题目,要求一屏只显示一道题目,点击下一题显示下一个题,思路也比较简单:
用一个num变量表示当前正在展示的题目索引
每次点击下一题按钮时num++
用v-if来判断 num===1,num===2这样来决定展示哪个。
这一写,模板里面好多啊,由于我们的题目每道题的模板可能都不一样,所以没办法循环,只能手写全部。之前考虑过用动态组件来切换,但是放弃了,因为没有if直观啊。
下面看怎么用jsx优化一下
//父组件 export default { name: "list", data() { return { data:'我是函数式组件', id:1, tests:{ 1:<div><span>第一道题</span></div>, 2:<div><section>第二道题</section></div>, 3:<div><p>第三道题</p></div> } } }, methods:{ next(){ ++this.id } }, render(){ return ( <div> <Item data={this.tests[this.id]}/> <button onClick={this.next}>下一题</button> </div> ) } }
上面每道题目的结构都不一致