組合式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步:
- 賦值在頂層:必須在setup頂層執(zhí)行賦值:
const instance = getCurrentInstance();
- 使用在周期鉤子里:必須在周期鉤子里使用窥淆,不得在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ā)事件
-
setup(props, context) {}
常規(guī)寫法的話拇惋,setup的第二個參數(shù)就是干這個的:
setup(props, context) {
context.emit('ooxx')
}
或者解構(gòu):
setup(props, { emit }) {
emit('ooxx')
}
- 語法糖寫法的話,先
const instance = getCurrentInstance();
抹剩,然后在生命周期鉤子或者用戶觸發(fā)事件里寫上instance.emit("xxx");
即可蚤假。
如何導(dǎo)出解構(gòu)的Proxy
如果要解構(gòu)Proxy,分2種情況討論:
如果property是基本類型數(shù)據(jù)吧兔,會丟失響應(yīng)磷仰,這時候應(yīng)當先
const ref = toRefs(Proxy)
,然后在return里解構(gòu)ref變量境蔼。如果你確定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里用不到,此時的最佳實踐:
盡量避免定義這種變量
給這種變量的變量名前面寫上下劃線粥血,表明是私有變量
<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的鍋匀借,因為任何編程方式都有最佳實踐一說:
- data方面
忘記古老的var
時代的最佳實踐颜阐。在古代,var
聲明的變量存在變量提升現(xiàn)象吓肋,為了防止愚蠢的程序員出了bug還搞不清為什么出bug凳怨,所以最佳實踐建議var
聲明變量永遠寫在作用域最頂部。現(xiàn)在是let
時代是鬼,并不需要這種最佳實踐猿棉,所以應(yīng)該就近聲明變量。這樣也就不會有所謂“data區(qū)域”了屑咳。
計算變量也是同樣道理萨赁。
- 周期鉤子方面
因為現(xiàn)在可以疊加設(shè)置周期鉤子,相信很少有蠢人會只定義一個鉤子兆龙。
鉤子應(yīng)緊隨業(yè)務(wù)杖爽,不要在本業(yè)務(wù)的鉤子里寫其他業(yè)務(wù)的內(nèi)容。
- methods方面
methods的本質(zhì)就是函數(shù)紫皇,函數(shù)聲明也應(yīng)做到就近聲明慰安,就近使用,千萬不要把函數(shù)故意提升到作用域頂部聪铺。
- 公用代碼方面
應(yīng)當放在頂部化焕,這是起碼的最佳實踐。
- 拆分組件
你一個組件5千行铃剔,你還不拆分撒桨,你要作死啊键兜?
- 多用混入等其他手段
就不多說了凤类。