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分為四個階段:
- Pending:當RFC作為PR提交時。
- Active:當RFC PR正在合併時。
- Landed:當RFC提出的更改在實際發行版中發佈時。
- Rejected:關閉RFC PR而不合併時。
本篇討論的RFC都在Active階段
刪除filters的支持
<!-- before --> {{ msg | format }} <!-- after --> {{ format(msg) }} 複製代碼
動機:
- 過濾器的功能可以輕鬆地通過方法調用或計算的屬性來複制,因此它主要提供語法而不是實用的價值。
- 過濾器需要一種自定義的微語法,該語法打破了表達式只是「 JavaScript」的假設-這增加了學習和實現成本。 實際上,它與JavaScript自己的按位或運算符(|)衝突,並使表達式解析更加複雜。
- 過濾器還會在模板IDE支持中增加額外的複雜性(由於它們不是真正的JavaScript)。
替代:
- 可以簡單的利用method替換filter的能力,統一語法,Vue.filter全局註冊的能力也可以用Vue.prototype全局掛載方法來實現。
- 目前有一個stage-1的提案pipeline-operator 可以優雅的實現方法組合。
let transformedMsg = msg |> uppercase |> reverse |> pluralize 複製代碼
render函數的改變
概覽:
- h現在已全局導入,而不是傳遞給渲染函數作為參數
- 渲染函數參數已更改,並使stateful組件和functional組件之間保持一致
- 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({}) 複製代碼
簡單的來說,如果你項目中只用到了observable
和nextTick
,那麼例如use
,reactive
等這些另外的api就不會被打包進你的項目中。
關於tree-shaking
,我特別喜歡的作者相學長有一篇文章可以看一下:
總結
在這個倉庫中,還有一些提案大家也可以自行去看一下,剩下的都是一些細節的優化,這些優化或多或少的會讓Vue3更好用一些,非常期待Vue3的到來。
另外由於plugin的存在,我已經在2.x中用Vue3的composition-api做了一些嘗鮮,不得不說真香!
Vue3 Composition-Api + TypeScript + 新型狀態管理模式探索