Vue3中不止composition-api,其他的提案(RFC)也很精彩。

  • 2020 年 4 月 11 日
  • 筆記

最近一段時間,Vue3帶來的新能力composition-api帶來了比較大的轟動,雖然是靈感是源React Hook,但是在很多方面卻超越了它。但是除了composition-api,其他的改動卻比較少有人討論,本篇文章就由vuejs/rfcs 這個倉庫來看看其他比較讓人振奮的RFC。

RFC其實就是(Request For Comments)徵求修正意見書,它不代表這個api一定會正式通過,但是卻可以讓社區知道vuejs團隊正在進行的一些工作,和一些新想法。

Vue的RFC分為四個階段:

  1. Pending:當RFC作為PR提交時。
  2. Active:當RFC PR正在合併時。
  3. Landed:當RFC提出的更改在實際發行版中發佈時。
  4. Rejected:關閉RFC PR而不合併時。

本篇討論的RFC都在Active階段

刪除filters的支持

<!-- before -->  {{ msg | format }}    <!-- after -->  {{ format(msg) }}  複製代碼

動機:

  1. 過濾器的功能可以輕鬆地通過方法調用或計算的屬性來複制,因此它主要提供語法而不是實用的價值。
  2. 過濾器需要一種自定義的微語法,該語法打破了表達式只是「 JavaScript」的假設-這增加了學習和實現成本。 實際上,它與JavaScript自己的按位或運算符(|)衝突,並使表達式解析更加複雜。
  3. 過濾器還會在模板IDE支持中增加額外的複雜性(由於它們不是真正的JavaScript)。

替代:

  1. 可以簡單的利用method替換filter的能力,統一語法,Vue.filter全局註冊的能力也可以用Vue.prototype全局掛載方法來實現。
  2. 目前有一個stage-1的提案pipeline-operator 可以優雅的實現方法組合。
let transformedMsg = msg |> uppercase |> reverse |> pluralize  複製代碼

render函數的改變

原文: github.com/vuejs/rfcs/…

概覽:

  1. h現在已全局導入,而不是傳遞給渲染函數作為參數
  2. 渲染函數參數已更改,並使stateful組件和functional組件之間保持一致
  3. VNode現在具有拉平的props結構

基本示例:

// globally imported `h`  import { h } from 'vue'    export default {    render() {      return h(        'div',        // flat data structure        {          id: 'app',          onClick() {            console.log('hello')          }        },        [          h('span', 'child')        ]      )    }  }  複製代碼

動機: 在2.x中,VNode是特定於上下文的-這意味着創建的每個VNode都綁定到創建它的組件實例(「上下文」),

在2.x中,這樣的一段代碼:

{      render(h) {          return h('div')      }  }  複製代碼

h其實是通過render中的形參傳入的,這是因為它需要關心是哪個組件實例在調用它,在3.x中,文章中介紹說vnode將會成為context free的,這意味着更加靈活的組件聲明位置(不止在.vue文件中,不需要到處傳遞h參數)。

並且如果context free真的實現,那麼在2.x中Vue高階組件的一些詬病也可以一同解決掉了,如果對context帶來的高階組件的bug感興趣的話,可以查看HcySunYang大大的這篇文章: segmentfault.com/p/121000001…

另外本篇中還提到了一個vnode的屬性拉平,

// before  {    class: ['foo', 'bar'],    style: { color: 'red' },    attrs: { id: 'foo' },    domProps: { innerHTML: '' },    on: { click: foo },    key: 'foo'  }    // after  {    class: ['foo', 'bar'],    style: { color: 'red' },    id: 'foo',    innerHTML: '',    onClick: foo,    key: 'foo'  }  複製代碼

目前看來,由於jsx最終會被編譯成生成vnode的方法,這個改動可能會讓vue中書寫jsx變得更加容易,現在的一些寫法可以看我寫的這篇文章: 手把手教你用jsx封裝Vue中的複雜組件(網易雲音樂實戰項目需求)

在這篇文章中可以看出,目前嵌套的vnode結構會讓jsx的書寫也變得很困難。

由於render函數的一些另外的細微變動,Vue3中理想的functional component的書寫方式是這樣的:

import { inject } from 'vue'  import { themeSymbol } from './ThemeProvider'    const FunctionalComp = props => {    const theme = inject(themeSymbol)    return h('div', `Using theme ${theme}`)  }  複製代碼

是不是很像React,哈哈。

全局方法的導入方式

為了更好的支持tree-shaking,Vue3把2.x中統一導出Vue的方式更改為分散導出,這樣只有項目中用到的方法會被打包進bundle中,有效的減少了包的大小。

import { nextTick, observable } from 'vue'    nextTick(() => {})    const obj = observable({})  複製代碼

簡單的來說,如果你項目中只用到了observablenextTick,那麼例如usereactive等這些另外的api就不會被打包進你的項目中。

關於tree-shaking,我特別喜歡的作者相學長有一篇文章可以看一下:

zhuanlan.zhihu.com/p/32831172

總結

在這個倉庫中,還有一些提案大家也可以自行去看一下,剩下的都是一些細節的優化,這些優化或多或少的會讓Vue3更好用一些,非常期待Vue3的到來。

另外由於plugin的存在,我已經在2.x中用Vue3的composition-api做了一些嘗鮮,不得不說真香

Vue3 Composition-Api + TypeScript + 新型狀態管理模式探索