Vue 3的組合式API以及ref語法糖學(xué)習(xí)

組合式API與配置項式API混合使用注意事項

  • 混合使用的話伏尼,setup(props, context) {}應(yīng)作為一個配置項API的一個配置項喝检,然后將它視為Vue 2的beforeCreate周期,在注冊components和props之后狱杰、在其他配置項加載之前執(zhí)行搬味。

  • 有人說setup(props, context) {}也可以視為created周期章郁,你最好別這么視為,這會引起很多誤解制市。

  • setup(props, context) {}所return的數(shù)據(jù)和方法如果與其他配置項的數(shù)據(jù)和方法重名抬旺,以setup() {}為準。無論書寫順序祥楣,其他配置項都無法覆蓋setup(props, context) {}的數(shù)據(jù)和方法开财。

  • 混合使用的話,不可以使用ref語法糖误褪。

  • import { reactive, ref, watch } from "vue"里面的這些方法可以在配置項API里使用责鳍,但是通常意義不大,因為配置項API基本沿用Vue 2的寫法(有些區(qū)別兽间,見官方文檔遷移辦法)薇搁。

setup(props, context) {}里為何不可用this關(guān)鍵字曹洽?

官方說的很清楚:

在setup(props, context) {}內(nèi)部挖胃,this不會是該活躍實例的引用,因為setup()是在解析其它組件選項之前被調(diào)用的惫东,所以setup()內(nèi)部的this的行為與其它選項中的this完全不同屎鳍。

setup(props, context) {}的this指向window宏娄,composition的文檔中也沒有提到怎么獲取組件實例,其實方法是:咱們可以通過getCurrentInstance()這個接口獲取Vue實例逮壁。

如何取得Vue實例孵坚?

用getCurrentInstance API,使用方法分2步:

  1. 賦值在頂層:必須在setup頂層執(zhí)行賦值:
const instance = getCurrentInstance();
  1. 使用在周期鉤子里:必須在周期鉤子里使用窥淆,不得在setup里使用:

雖然const instance = getCurrentInstance()必須在頂層卖宠,但是此時獲取不到上下文,必須寫到onBeforeMount(() => {})或其他周期函數(shù)里才能獲取上下文忧饭。

  setup(props, context) {
    const instance = getCurrentInstance();
    onBeforeMount(() => {
      console.log(instance.data);
    });
  }

如何訪問this扛伍、配置項的data和methods

訪問組件實例this、配置項data词裤、配置項methods的辦法:

  • 使用組件實例this刺洒,就用instance.proxy鳖宾。

  • 訪問配置項的data,就用instance.data逆航,它具備響應(yīng)式鼎文。

  • 執(zhí)行配置項的methods,就用instance.ctx.foo()因俐。

向父組件派發(fā)事件

  1. setup(props, context) {}常規(guī)寫法的話拇惋,setup的第二個參數(shù)就是干這個的:
setup(props, context) {
  context.emit('ooxx')
}

或者解構(gòu):

setup(props, { emit }) {
  emit('ooxx')
}
  1. 語法糖寫法的話,先const instance = getCurrentInstance();抹剩,然后在生命周期鉤子或者用戶觸發(fā)事件里寫上instance.emit("xxx");即可蚤假。

如何導(dǎo)出解構(gòu)的Proxy

如果要解構(gòu)Proxy,分2種情況討論:

  1. 如果property是基本類型數(shù)據(jù)吧兔,會丟失響應(yīng)磷仰,這時候應(yīng)當先const ref = toRefs(Proxy),然后在return里解構(gòu)ref變量境蔼。

  2. 如果你確定Proxy所有一級property的值都是引用類型灶平,可以放心解構(gòu)Proxy。

生命周期鉤子可以寫到函數(shù)里

函數(shù)里可以寫生命周期鉤子箍土,只要函數(shù)比周期執(zhí)行的早就可以:

function fun1() {
  // 這里可以用onMounted執(zhí)行代碼
  onMounted(() => {})
}

Ref語法糖

實現(xiàn)的前提是:首先給script標簽加上setup標記逢享,也就是<script setup>,然后吴藻,不允許再使用配置項式API瞒爬。

不再需要寫export default{}

這很棒。

原本是:

<script>
import {onBeforeMount, onMounted} from 'vue'

export default {
  name: 'App',
  setup() {
      onBeforeMount(() => {
          // 在掛載前執(zhí)行某些代碼
      });
      onMounted(() => {
          // 在掛載后執(zhí)行某些代碼
      });
      return {};
  }
}
</script>

現(xiàn)在是:

<script setup>
import { reactive, onBeforeMount, onMounted } from "vue";
const a = reactive({ x: 1 });
onBeforeMount(() => {
  a.x = 2;
});
onMounted(() => {
  a.x = 3;
});
</script>

直接向<template>暴露頂層變量

編譯器會自動收集頂層變量沟堡,然后return侧但,所以你不需要寫return,如果寫了反而報錯航罗。這很棒禀横。

有些變量在template里用不到,此時的最佳實踐:

  1. 盡量避免定義這種變量

  2. 給這種變量的變量名前面寫上下劃線粥血,表明是私有變量

<template>
  <div>
    <button @click="r.b.c++">count is: {{ r.b.c }}</button>
  </div>
</template>

<script setup>
import { reactive } from "vue";

let r = reactive({ a: 1, b: { c: 2 } });
</script>

ref標簽

ref: t = 10;約等價于let t = ref(10)柏锄,依然有些區(qū)別,先看例子:

ref: t = 10;
console.log(t); // 10
console.log(t + 1); // 11
console.log(t.value); // undefined
console.log($t); // ref對象
console.log($t + 1); // [object Object]1
console.log($t.value + 1); // 11

也就是說复亏,聲明ref: t = 10之后:

  • t返回ref對象的內(nèi)部值趾娃,而不是ref對象本身
  • t.value返回undefined
  • t前加$符號返回ref對象
  • $t.value返回內(nèi)部值
  • t對于template來講是ref對象

這個ref:標簽是社區(qū)最大的爭議點,它的好處是你可以在js里把t當做內(nèi)部值來隨意運算缔御,而template也自動把它當做ref對象抬闷。當你需要在js里調(diào)用ref對象的時候,你可以用$t刹淌,雖然加$也是一種心智負擔(dān)饶氏,但是這種需求概率太低了,因為你極少需要獲取ref對象有勾。這就是Vue創(chuàng)始人推薦使用ref:標簽的理由疹启。

我建議盡量使用ref:標簽,除非你真的很討厭這種語法糖蔼卡。

使用<script setup>標簽喊崖,如何獲取props和context?

沒使用<script setup>標簽的時候雇逞,setup(props, context) {}自帶參數(shù)用來獲取props和context荤懂,現(xiàn)在setup(props, context) {}已經(jīng)省略了,如何獲取props和context呢塘砸?

1. 使用useContext獲取context

useContext()返回的內(nèi)容跟不用<script setup>標簽時候setup(props, context) {}的context的返回內(nèi)容完全一致节仿。

console.log(useContext());

2. 使用defineProps接收props

defineProps({
  msg: String
})

或:

defineProps({
  msg: {
    type: String,
    default: ''
})

3. 借助useContext使用props

const ctx = useContext();
console.log(ctx.props);

4. 允許直接修改props

Vue 2中不允許直接修改props,得用this.$emit掉蔬,但是Vue 3允許直接修改廊宪,只不過修改的是組件內(nèi)props的值,并不會影響父組件的傳入值女轿。

有時候直接修改props很有用箭启,比如父組件將ajax的結(jié)果數(shù)據(jù)給子組件,子組件修改數(shù)據(jù)并不需要通知父組件蛉迹,父組件也沒興趣知道修改成什么傅寡,這時候子組件直接修改數(shù)據(jù)即可。

5. 不要解構(gòu)props

最好不要解構(gòu)props北救,也就是說最好分開傳入props荐操,如果props的property是基本類型數(shù)據(jù),會導(dǎo)致響應(yīng)式丟失珍策,對它的修改會反映不到DOM上淀零。

在setup中調(diào)用store

在Vue2中使用 Vuex,我們都是通過this.$store來與獲取到Vuex實例膛壹,但上一部分說了原本Vue2中的this的獲取方式不一樣了驾中,并且我們在Vue3的getCurrentInstance().proxy中也沒有發(fā)現(xiàn)$store這個屬性,那么如何獲取到Vuex實例呢模聋?這就要通過vuex中的一個方法了肩民,即useStore

// store 文件夾下的 index.js
import Vuex from 'vuex'

const store = Vuex.createStore({
    state: {
        name: '王XX',
        age: 18
    },
    mutations: {
        // ……
    },
    // ……
})
// example.vue
<script>
// 從 vuex 中導(dǎo)入 useStore 方法
import {useStore} from 'vuex'
export default {
    setup() {   
        // 獲取 vuex 實例
        const store = useStore()

        console.log(store)
    }
}
</script>

然后接下來就可以像之前一樣正常使用vuex了链方。

如何避免用配置項思維編寫組合式代碼持痰?

有人說,很多人編寫組合式API依然習(xí)慣用配置項思維祟蚀,最終還是會形成data區(qū)域工窍、computed區(qū)域割卖、周期鉤子區(qū)域、methods區(qū)域等患雏。如果趕上“隨緣”性格的程序員鹏溯,他會連區(qū)域都不分,只會東一榔頭西一棒槌式的隨意編寫淹仑,使用組合式API反而更亂丙挽。

其實,這不是組合式API的鍋匀借,因為任何編程方式都有最佳實踐一說:

  1. data方面

忘記古老的var時代的最佳實踐颜阐。在古代,var聲明的變量存在變量提升現(xiàn)象吓肋,為了防止愚蠢的程序員出了bug還搞不清為什么出bug凳怨,所以最佳實踐建議var聲明變量永遠寫在作用域最頂部。現(xiàn)在是let時代是鬼,并不需要這種最佳實踐猿棉,所以應(yīng)該就近聲明變量。這樣也就不會有所謂“data區(qū)域”了屑咳。

計算變量也是同樣道理萨赁。

  1. 周期鉤子方面

因為現(xiàn)在可以疊加設(shè)置周期鉤子,相信很少有蠢人會只定義一個鉤子兆龙。

鉤子應(yīng)緊隨業(yè)務(wù)杖爽,不要在本業(yè)務(wù)的鉤子里寫其他業(yè)務(wù)的內(nèi)容。

  1. methods方面

methods的本質(zhì)就是函數(shù)紫皇,函數(shù)聲明也應(yīng)做到就近聲明慰安,就近使用,千萬不要把函數(shù)故意提升到作用域頂部聪铺。

  1. 公用代碼方面

應(yīng)當放在頂部化焕,這是起碼的最佳實踐。

  1. 拆分組件

你一個組件5千行铃剔,你還不拆分撒桨,你要作死啊键兜?

  1. 多用混入等其他手段

就不多說了凤类。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市普气,隨后出現(xiàn)的幾起案子谜疤,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夷磕,死亡現(xiàn)場離奇詭異履肃,居然都是意外死亡,警方通過查閱死者的電腦和手機坐桩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門尺棋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人撕攒,你說我怎么就攤上這事陡鹃『嫫郑” “怎么了抖坪?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長闷叉。 經(jīng)常有香客問我擦俐,道長,這世上最難降的妖魔是什么握侧? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任蚯瞧,我火速辦了婚禮,結(jié)果婚禮上品擎,老公的妹妹穿的比我還像新娘埋合。我一直安慰自己,他們只是感情好萄传,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布甚颂。 她就那樣靜靜地躺著,像睡著了一般秀菱。 火紅的嫁衣襯著肌膚如雪振诬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天衍菱,我揣著相機與錄音赶么,去河邊找鬼。 笑死脊串,一個胖子當著我的面吹牛辫呻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播琼锋,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼印屁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了斩例?” 一聲冷哼從身側(cè)響起雄人,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后础钠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恰力,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年旗吁,在試婚紗的時候發(fā)現(xiàn)自己被綠了踩萎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡很钓,死狀恐怖香府,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情码倦,我是刑警寧澤企孩,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站袁稽,受9級特大地震影響勿璃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜推汽,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一补疑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧歹撒,春花似錦莲组、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鳞尔,卻和暖如春嬉橙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寥假。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工市框, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糕韧。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓枫振,卻偏偏與公主長得像,于是被迫代替她去往敵國和親萤彩。 傳聞我的和親對象是個殘疾皇子粪滤,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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