# SCF还是JSX

之前不怎么思考这类的问题,长期使用 vue开发的过程中,也没觉得不爽的地方,可能是因为接触比较多的是业务代码和移动端开发

之所以会有这样的思考,是因为后来接触了使用 VUE 开发 PC 后台,PC 的项目的特点就是页面需要承载的内容非常多,所以业务也相对比较复杂,当内容越来越多时,为了减肥就会去抽离成组件的方法进行组装页面,封装得越多彼此的通信越多,用到的 slot,mininx 的地方也越多,这个时候就越来越感觉到项目好难看得明白

这就是会思考题目的来源

# SFC

SFC 即 Single File Component,也即单文件组件,Vue 组件就是很明显的SFC

一个vue组件包含了模板和Vue api和样式,一个组件的功能及包装的代码非常得完整用也一目了然,这也是一直都觉得使用 vue 非常舒服的原因,队了这些 Vue 使用 SFC 还以下优点:

通过对模板的分析,可以做一些前期优化,这点是JSX语法很难以做到的

例如“静态树提升”优化:

如下一段模板(这是模板,并非JSX):

<template>
 <div>
   <span>static</span>
   <span>{{ dynamic }}</span>
 </div>
</template>

如果不做任何优化,那么编译后得到的代码应该是这样子:

render() {
 return h('div', [
   h('span', 'static'),
   h('span', this.dynamic)
 ]);
} 

那么每次重新渲染时,都会执行3次 h 方法,虽然未必会触发真正的DOM更新,但这也是一部分开销。

通过观察,我们知道 h('span', 'static') 这段代码传入的参数始终都不会有变化,它是静态的,而只有 h('span', this.dynamic) 这段才会根据 dynamic 的值变化。

在Vue 3.0中,编译器会自动分析出这种区别,对于静态的节点,会自动提升到 render 方法外部,避免重复执行。

Vue 3.0编译后的代码:

const __static1 = h('span', 'static');

render() {
   return h('div', [
       __static1,
       h('span', this.dynamic)
    ])     
}

这样每次渲染时就只会执行两次 h 。换言之,经过静态树提升后,Vue 3.0渲染成本将只会和动态节点的规模相关,静态节点将会被复用。

除了静态树提升,还有很多别的编译阶段的优化,这些都是JSX语法难以做到的,因为JSX语法本质上还是在写JS,它没有任何限制,强行提升它会破坏JS执行的上下文,所以很难做出这种优化(也许配合 prepack 可以做到)。

考虑到这一点,如果你是在实现一个对性能要求较高的基础组件库,那模板语法仍然是首选。

另外JSX也没办法做 ref 自动展开,使得 ref 和 reactive 在使用上没有太大区别。

# SFC的问题

以VUE 为便,当一个组件开发变得复杂的时候可能会出现以下问题:

组件扩展节点

vue中如在一个组件中希望能显示外部自定义的节点时,需要使用 slot, slot 这个东西每次用都觉得便扭,便扭的原因是其绕来绕去的作用域

同样的功能在 react 中实现就比较直观

const Comp = () => <Layout header={<MyHeader />} footer={<MyFooter />} />

或者将函数组件当作参数往别个函数组件中传,这种写法更符合咱们的常规思维

组件要注册才能用

vue 要使用组件,必需先注册该组件,如果想绕过注册这一步,只能使用渲染函数

minxin

这个就是自己用得爽,看别人就是不爽的东西

组件通信

同层级且组件通信少的情况下还好,一旦组件数量变多且出现深层组件通信时,简直噩梦,当然这应该不是只有 vue 才会出现的问题

JSX 本质上就是一个函数,应用的组成就是 函数彼此调用的过程,可以灵活得使用 JS 做任何事情,所以在做 公共组件,以及高度灵活的组件时,使用 JSX 将更方便

日后在 VUE3项目中中 会尝试使用 JSX和SFC 结合的方法,具体感觉一下开发体验是否有改善