vue2 + Composition API 實踐

響應(yīng)式API

  • ref
  • unref
  • toRef
  • toRefs
  • isRef
  • customRef
  • shallowRef
  • triggerRef
  • computed
  • watch
  • watchEffect
1赫模、解構(gòu)帶來的響應(yīng)式陷阱

我們習(xí)慣了ES6的對象解構(gòu)風(fēng)格聘萨,但這在composition- api里可能會有陷阱绎速。因為結(jié)構(gòu)可能會讓你的響應(yīng)式對象失去預(yù)期中的響應(yīng)特性讯柔。

<template>
  <div id="app">
    {{count}}
    <button @click="addCount"></button>
  </div>
</template>
<script>
import { reactive } from '@vue/runtime-dom'
export default {
  setup() {
    const data = reactive({
      count: 0
    })
    function addCount() {
      data.count += 1
    }
    return {
        data,
        count: data.count,
        addCount
    }
  }
};
</script>

比如這里师骗,button的click時候屁擅,不會得到預(yù)期的count的增加仲义。因為setup執(zhí)行返回的count并不是響應(yīng)式的插佛。
也就是說杠巡,雖然你的click事件確實的改變了data.count的值,但是這個值并沒有響應(yīng)式的去改變其他引用這個值的地方雇寇。怎么去驗證我們這個解釋呢氢拥?

我們可以開著chrome的vue插件,定位到你的組件锨侯。然后你可以點擊一下button嫩海,可以看到count并沒有變化,data呢囚痴?看起來好像也沒有變化叁怪?這不是不符合邏輯嗎?甚至我們在click的回調(diào)函數(shù)里打印一下發(fā)現(xiàn)是有執(zhí)行data.count+1 這個操作的深滚。
事實是奕谭,data.count確實是執(zhí)行了的,但是因為不是reactive的痴荐,所以插件里沒有及時更新這個新數(shù)據(jù)血柳。如果你把插件先切到別的組件上去,再切回來生兆。你就會發(fā)現(xiàn)难捌,data.count是符合預(yù)期的!

click操作前的插件看到的數(shù)據(jù):


image

我做了2次click后鸦难,現(xiàn)在插件里把光標(biāo)切到別的組件上根吁,再切回來。就可以看到data的變化:


image.png

只是引用了data.count的地方?jīng)]有被更新合蔽,這就說明引用data.count的地方是非reactive的婴栽。

我們要要做的,就是改造一下引用data.count的地方辈末。我們在setup里的返回愚争,可以用computedtoRefs來改造一下返回值。

再看一下toRefs改造后的demo:

<template>
  <div id="app">
    {{count}}
    <button @click="addCount"></button>
  </div>
</template>
<script>
import { reactive } from '@vue/runtime-dom'
export default {
  setup() {
    const data = reactive({
      count: 0
    })
    function addCount() {
      data.count += 1
    }
    return {
      ...toRefs(data),
      addCount
    }
  }
};
</script>

第二個問題來了:toRefs一定是安全應(yīng)對解構(gòu)的方案么挤聘?

不是的轰枝,因為toRefs的結(jié)構(gòu)是淺解構(gòu)的,對于我們demo里的這種簡單的對象是work的组去。但是如果是一個嵌套很深的復(fù)雜Object鞍陨,還是會有解構(gòu)后響應(yīng)式斷裂的問題。如果數(shù)據(jù)的層級比較復(fù)雜,建議使用computed诚撵。

2缭裆、watch 和 watchEffect

watchEffect 很像React里的useEffect,是一個副作用函數(shù)寿烟。用法也基本一致澈驼。

watch的話,接收2個參數(shù)筛武。第一個參數(shù)是watch的target缝其,看ts結(jié)構(gòu),必須是一個ref對象或者computedRef對象徘六;第二個參數(shù)是watch的回調(diào)函數(shù)内边。

踩坑:
目前@vue/composition-api里的watch有bug。在watch一個數(shù)組的時候待锈,觸發(fā)不了回調(diào)函數(shù),從v1.1版本開始就有這個問題漠其。已經(jīng)有人提了issue,暫未解決(no longer works for multiple sources after v1.1)竿音。

3和屎、composition-api模仿React的useContext

React的hooks出來之后,有個很好用的東西就是Context谍失,很像一個微型Redux眶俩,可以很好的跨組件傳值莹汤,尤其是在組件粒度很細(xì)的時候快鱼,我們的組件間通信頻率也會升高。

之前vue2的時代纲岭,其實一直有provideinject可以用抹竹。但是provideinject的對象一般是非響應(yīng)式的。官網(wǎng)是這么記載的:

image.png

vue2的時候止潮,我們一般不太注重如何把一個數(shù)據(jù)變成響應(yīng)式的(也不是沒有辦法窃判,比如Vue.observable(obj)可以把一個對象變成響應(yīng)式的。如果我們把這個對象provide出去喇闸,那么傳遞的數(shù)據(jù)也就一直是響應(yīng)式的了)袄琳。

vue3(或者vue2 + @vue/composition-api)后,我們更多的關(guān)注到了數(shù)據(jù)的reactive特性燃乍。比如用ref或者reactive關(guān)鍵字來構(gòu)造一個響應(yīng)式的對象唆樊。我們?nèi)绻儆?code>provide直接傳遞一個reactive的對象,豈不是可以模擬出類似React的useContext這樣的結(jié)構(gòu)刻蟹?

外層Context層構(gòu)造:
import { createApp, defineComponent, provider, inject, reactive, readonly, toRefs } from 'vue';
// Provider 包裝組件
const MyConfigProvider = defineComponent({
    name: 'MyConfigProvider',
    props: ['prefixCls', 'title'],
    setup (props, { slots }: SetupContext) {
        const { prefixCls, title } = toRefs(props);
        const context = reactive({
          prefixCls,
          title
        });
        provide('myConfig', readonly(context));
        return () => slots.default?.();
    }
});

// 測試用子組件
const ChildComp = defineComponent({
    name: 'ChildComp',
    setup () {
        const myConfig = inject('myConfig', {});

        return () => (
            <>
                <p>{myConfig.prefixCls}</p>
                <p>{myConfig.title}</p>
            </>
        )
    }
});


// 調(diào)用Context層和子組件
const App = defineComponent({
    name: 'App',
    setup () {
        const state = reactive({
          prefixCls: 'myui',
          title: 'MyApp',
          i18n: (key: string) => key
        });
        return () => (
            <div id="#app">
                <MyConfigProvider {...state}>
                    <ChildComp />
                </MyConfigProvider>
            </div>
        )
    }
});


本身vue3(or vue2 + @vue/composition-api)也是支持hooks的逗旁。

這樣我們就可以按照React hooks的開發(fā)習(xí)慣去給vue抽hooks了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舆瘪,一起剝皮案震驚了整個濱河市片效,隨后出現(xiàn)的幾起案子红伦,更是在濱河造成了極大的恐慌,老刑警劉巖淀衣,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昙读,死亡現(xiàn)場離奇詭異,居然都是意外死亡舌缤,警方通過查閱死者的電腦和手機(jī)箕戳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來国撵,“玉大人陵吸,你說我怎么就攤上這事〗檠溃” “怎么了壮虫?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長环础。 經(jīng)常有香客問我囚似,道長,這世上最難降的妖魔是什么线得? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任饶唤,我火速辦了婚禮,結(jié)果婚禮上贯钩,老公的妹妹穿的比我還像新娘募狂。我一直安慰自己,他們只是感情好角雷,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布祸穷。 她就那樣靜靜地躺著,像睡著了一般勺三。 火紅的嫁衣襯著肌膚如雪雷滚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天吗坚,我揣著相機(jī)與錄音祈远,去河邊找鬼。 笑死商源,一個胖子當(dāng)著我的面吹牛车份,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播炊汹,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼躬充,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起充甚,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤以政,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伴找,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盈蛮,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年技矮,在試婚紗的時候發(fā)現(xiàn)自己被綠了抖誉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡衰倦,死狀恐怖袒炉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情樊零,我是刑警寧澤我磁,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站驻襟,受9級特大地震影響夺艰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沉衣,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一郁副、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧豌习,春花似錦存谎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽草雕。三九已至巷屿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間墩虹,已是汗流浹背嘱巾。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留诫钓,地道東北人旬昭。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像菌湃,于是被迫代替她去往敵國和親问拘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容