composition API 和 Mixins

關(guān)于Vue3.0的Composition API 和 舊版本的Mixins【轉(zhuǎn)載】

原文:http://caibaojian.com/vue3-composition-api.html


在過往,如果你想共享組件間的代碼屁柏,一般使用的方式是利用 mixin 來實(shí)現(xiàn)。但是在Vue3.0 中提供了更好的解決方案 Composition API抖甘。

下面我們將介紹 Mixins 的缺點(diǎn),并且看看 Composition API 是如何克服這些缺點(diǎn)的蘑斧。

Mixins簡述

我們先來回顧以下Mixins的模式老厌。以下的內(nèi)容是十分重要的需要認(rèn)真閱讀。

通常情況下肃弟,一個(gè)Vue組件是由一個(gè)Javascript對象來定義的,這個(gè)Javascript對象具有各種屬性零蓉,代表著我們需要的功能 --- 比如data,method,computed等笤受。

    // MyComponent.js
    export default {
        data:()=>({
             myDataProperty: null
        }),
        methods:{
            myMethod () { ... }
        },
        // ....
    }

當(dāng)我們想在組件之間共享相同的屬性的時(shí)候,就可以將共同的屬性提取出來敌蜂,存放到一個(gè)單獨(dú)的模塊中箩兽。

    // MyMixins.js
    export default {
        data:()=>({
            mySharedDataProperty: null
        }),
        methods:{
            blabla(){...}
        }
    }

現(xiàn)在我們通過將其分配給 mixin config 屬性并將其添加到任何使用的組件中。在運(yùn)行時(shí)章喉,Vue將把組件的屬性與任何添加的 mixin 合并

    // ConsumingComponent.js
    import MyMixin from "./MyMixin.js";

    export default {
        mixins: [MyMixin],
        data: () => ({
            myLocalDataProperty: null
            }),
        methods: {
            myLocalMethod () { ... }
            }
        }

在這個(gè)具體的例子中汗贫,運(yùn)行時(shí)使用的組件定義是這樣的身坐。

    export default {
        data:()=>({
             mySharedDataProperty: null
             myLocalDataProperty: null
        }),
        methods:{
            mySharedMethod () { ... },
            myLocalMethod () { ... }
        }
    }

Mixins 缺點(diǎn)

1. 命名沖突

我們看到minxin模式是如何在運(yùn)行時(shí)合并兩個(gè)對象的。如果它們都共享一個(gè)同名的屬性會發(fā)生什么

    const mixin = {
        data: ()=>({
            myProp:null
        })
    }

    export default {
        mixins:[mixin],
        data:()=>({
            // same name !
            myProp:null
        })
    }

這就是合并策略發(fā)揮的地方芳绩。這一組規(guī)則用于決定一個(gè)組件包含多個(gè)相同名稱的選項(xiàng)時(shí)的情況。

Vue組件的默認(rèn)(但可選擇配置)合并策略決定了本地選項(xiàng)將覆蓋混合器選項(xiàng)撞反。但也有例外妥色,例如我們有多個(gè)相同類型的生命周期鉤子,那么這些鉤子將被添加到鉤子數(shù)組中遏片,并且所有的鉤子將被依次調(diào)用嘹害。

盡管我們不應(yīng)該遇到任何實(shí)際的錯(cuò)誤,但當(dāng)我們在多個(gè)組件和混合體之間雜耍命名的屬性時(shí)吮便,寫代碼會越來越困難笔呀。尤其當(dāng)?shù)谌降幕旌辖M件被添加為npm包時(shí),就更難了髓需,因?yàn)樗鼈兊拿麑傩钥赡軙饹_突许师。

2.隱含的依賴關(guān)系

混合器和消耗它的組件之間沒有層次關(guān)系。這意味著僚匆,組件可以使用混入器中定義的數(shù)據(jù)屬性(如mySharedDataProperty)微渠,但混入器也可以使用它假定在組件中定義的數(shù)據(jù)屬性(如myLocalDataProperty)。當(dāng)混合器被用于共享輸入驗(yàn)證時(shí)咧擂,通常會出現(xiàn)這種情況逞盆。mixin可能會期望一個(gè)組件有一個(gè)輸入值,它將在自己的validate方法中使用松申。

但這可能會導(dǎo)致問題云芦。如果我們以后想重構(gòu)一個(gè)組件并改變了mixin需要的變量的名稱,我們會發(fā)現(xiàn)在運(yùn)行時(shí)會出現(xiàn)報(bào)錯(cuò)贸桶。

現(xiàn)在想象一下一個(gè)有一大堆 mixin 的組件舅逸,我們可以重構(gòu)本地?cái)?shù)據(jù)嗎?我們可以重構(gòu)一個(gè)本地?cái)?shù)據(jù)屬性嗎皇筛?或者會不會破壞一個(gè)混搭堡赔?哪一個(gè)混雜項(xiàng)呢?我們必須手動搜索它們才能知道设联。

這些缺點(diǎn)的存在善已,就是Composition API背后的主要?jiǎng)右蛑唬旅嫦却致缘慕榻B了Composition API的工作原理

關(guān)于Composition API 的工作原理

組成API 的關(guān)鍵思想是离例,我們將組件的功能(如狀態(tài)换团,方法,計(jì)算屬性等)定義為對象屬性宫蛆,而不是將其定義為從新得設(shè)置函數(shù)中返回的Javascript變量

以這個(gè)經(jīng)典的Vue 2組件為例艘包,它定義了一個(gè) "計(jì)數(shù)器 "功能的猛。

    // counter.Vue
    export default = {
        data:()=>({
            count:0
        }),
        methods:{
            increment(){
                this.count++
            }
        },
        computed:{
            double(){
                return this.count * 2
            }
        }
    }

下面是Composition API 定義的完全相同的組件

    // Counter.vue
    import {ref, computed } from "vue";

    export default ={
        setup(){
            const count = ref(0)
            const double = computed( ()=> count * 2 )
            function increment(){
                count.value++;
            }
            return {
                count,
                double,
                increment
            }
        }
    }

tips

  • 反應(yīng)式變量: 在一個(gè) Y = f(x) 的函數(shù)中 Y隨著X的變化而變化,那么 Y 就是反應(yīng)式變量(又叫因變量)

首先你會注意到我們導(dǎo)入了一個(gè) ref 函數(shù)想虎,這使得我們可以定義一個(gè)反應(yīng)式變量,其功能與數(shù)據(jù)變量基本相同卦尊。計(jì)算函數(shù)也一樣

增量方法(increment)不是反應(yīng)式的,所以它可以被聲明為一個(gè)普通的Javascript函數(shù)舌厨。注意岂却,我們需要改變子屬性值,才能改變 count 反應(yīng)式變量的值裙椭。這是因?yàn)槭褂?ref 創(chuàng)建的反應(yīng)式變量在傳遞過程中躏哩,需要將其作為對象來保留反應(yīng)式變量

關(guān)于 ref 的工作原理的詳細(xì)解釋,請參考 Vue Composition API 文檔揉燃,這是個(gè)好主意扫尺。

一旦我們定義了這些功能,我們就從setup函數(shù)中返回這些功能炊汤。上面的兩個(gè)組件在功能上沒有什么區(qū)別正驻。我們所做的就是使用替代API。

代碼提取

Composition API 的第一個(gè)明顯的優(yōu)勢是很容易提取邏輯

讓我們用Composition API重構(gòu)上面定義的組件抢腐,這樣我們定義的特征就在一個(gè)Javascript模塊useCounter中拨拓。(用"use"作為特征描述的前綴是Composition API的命名慣例)

    // useCounter.js
    import { ref, computed } from "vue";

    export default function () {
        const count = ref(0);
        const double = computed( () => count * 2 )
        function increment () {
            count.value++;
        }
        return {
            count,
            double,
            increment
        }
    }

代碼重用

要在組件中使用該功能,我們只需將模塊導(dǎo)入到組件文件中氓栈,然后調(diào)用它(注意渣磷,導(dǎo)入是一個(gè)函數(shù))。這將返回我們定義的變量授瘦,隨后我們可以從 setup 函數(shù)中返回這些變量

    // MyComponent.js
    import useCounter from "./useCounter.js";

    export default {
        setup () {
            const { count, double, increment } = useCounter()   // 解構(gòu)
            return {
                count,
                double,
                increment
            }
        }
    }

這一切可能看起來有點(diǎn)啰嗦醋界,也沒有意義,但是讓我們來看看這個(gè)模式如何克服我們前面看到的 mixins 的問題

命名沖突 解決了!

我們之前已經(jīng)看到了一個(gè)混搭元素如何使用可能與消耗組件中的屬性名稱相同的屬性提完,甚至更陰險(xiǎn)的是形纺,在消耗組件使用的其他混搭元素中也會有相同的名稱

這并不是 Composition API 的問題,因?yàn)槲覀冃枰@式命名任何狀態(tài)或從組成函數(shù)返回的方法

    export default {
        setup(){
            const {someVar1, someMethod1 } = useCompFunction1()
            const {someVar2, someMethod2 } = useCompFunction2()
            return {
                someVar1,
                someMethod1,
                someVar2,
                someMethod2
            }
        }
    }

命名碰撞的解決方法將與其他任何Javascript變量的命名方式一樣徒欣。

隱式依賴關(guān)系 解決了逐样!

我們之前也看到了一個(gè)組合函數(shù)可能會使用消耗組件上定義的數(shù)據(jù)屬性,這可能會使代碼變得很脆弱打肝,而且很難推理

而組合函數(shù)也可以調(diào)用消耗消耗組件中定義得變量脂新。但不同的是,這個(gè)變量現(xiàn)在必須顯式傳遞給組成函數(shù)

    import useCompFunction from "./useCompFunction";

    export default {
        setup () {
            // some local value the a composition function needs to use
            const myLocalVal = ref(0);

            // it must be explicitly passed as an argument
            const {...} = useCompFunction(myLocalVal)
        }
    }

包裝起來

mixin 模式表面上看起來很安全粗梭。然而争便,通過合并對象來共享代碼,由于它給代碼增加了脆弱性断医,并且覆蓋了推理功能的能力滞乙,因此成為了一種反模式

Composition API 最聰明的地方在于奏纪,它允許 Vue 依靠原生 Javascript 內(nèi)置的保障措施來共享代碼,比如將變量傳遞給函數(shù)斩启,以及模塊系統(tǒng)序调。

這是否意味著 Composition API 在各方面都比 Vue的經(jīng)典 API 優(yōu)越呢?不是的兔簇,在大多數(shù)情況下发绢,你可以堅(jiān)持使用經(jīng)典的API。但是男韧,如果你打算重用代碼朴摊,Composition API 是更加優(yōu)越的默垄。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末此虑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子口锭,更是在濱河造成了極大的恐慌朦前,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹃操,死亡現(xiàn)場離奇詭異韭寸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)荆隘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門恩伺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人椰拒,你說我怎么就攤上這事晶渠。” “怎么了燃观?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵褒脯,是天一觀的道長。 經(jīng)常有香客問我缆毁,道長番川,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任脊框,我火速辦了婚禮颁督,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浇雹。我一直安慰自己适篙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布箫爷。 她就那樣靜靜地躺著嚷节,像睡著了一般聂儒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上硫痰,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天衩婚,我揣著相機(jī)與錄音,去河邊找鬼效斑。 笑死非春,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缓屠。 我是一名探鬼主播奇昙,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼敌完!你這毒婦竟也來了储耐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤滨溉,失蹤者是張志新(化名)和其女友劉穎什湘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晦攒,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡闽撤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脯颜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哟旗。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖栋操,靈堂內(nèi)的尸體忽然破棺而出闸餐,到底是詐尸還是另有隱情,我是刑警寧澤讼庇,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布绎巨,位于F島的核電站,受9級特大地震影響蠕啄,放射性物質(zhì)發(fā)生泄漏场勤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一歼跟、第九天 我趴在偏房一處隱蔽的房頂上張望和媳。 院中可真熱鬧,春花似錦哈街、人聲如沸留瞳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽她倘。三九已至璧微,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間硬梁,已是汗流浹背前硫。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荧止,地道東北人屹电。 一個(gè)月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像跃巡,于是被迫代替她去往敵國和親危号。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359