reactive()
還有另一種聲明響應(yīng)式狀態(tài)的方式,即使用 reactive() API。與將內(nèi)部值包裝在特殊對象中的 ref 不同,reactive() 將使對象本身具有響應(yīng)性:
-
「點(diǎn)擊按鈕+1」
<script?lang="ts"?setup>
import?{?reactive?}?from?'vue'
const?state?=?reactive({?count:?0?})
</script>
<template>
????<div?class="container">
????????<button?@click="state.count++">
????????????點(diǎn)擊次數(shù)加+1?:?{{?state.count?}}
????????</button>
????</div>
</template>
<style?lang="scss"?scoped>
.container?{}
</style>
-
「示例效果」
響應(yīng)式對象是 JavaScript 代理,其行為就和普通對象一樣。不同的是,Vue 能夠攔截對響應(yīng)式對象所有屬性的訪問和修改,以便進(jìn)行依賴追蹤和觸發(fā)更新。
reactive() 將深層地轉(zhuǎn)換對象:當(dāng)訪問嵌套對象時,它們也會被 reactive() 包裝。當(dāng) ref 的值是一個對象時,ref() 也會在內(nèi)部調(diào)用它。與淺層 ref 類似,這里也有一個 shallowReactive() API 可以選擇退出深層響應(yīng)性。
-
reactive() 返回的是一個原始對象的 Proxy,它和原始對象是不相等的
const?raw?=?{}
const?proxy?=?reactive(raw)
//?代理對象和原始對象不是全等的
console.log(proxy?===?raw)?//?false
只有代理對象是響應(yīng)式的,更改原始對象不會觸發(fā)更新。
因此,使用 Vue 的響應(yīng)式系統(tǒng)的最佳實(shí)踐是 「僅使用你聲明對象的代理版本」。
-
為保證訪問代理的一致性,對同一個原始對象調(diào)用 reactive() 會總是返回同樣的代理對象,而對一個已存在的代理對象調(diào)用 reactive() 會返回其本身:
//?在同一個對象上調(diào)用?reactive()?會返回相同的代理
console.log(reactive(raw)?===?proxy)?//?true
//?在一個代理上調(diào)用?reactive()?會返回它自己
console.log(reactive(proxy)?===?proxy)?//?true
這個規(guī)則對嵌套對象也適用。依靠深層響應(yīng)性,響應(yīng)式對象內(nèi)的嵌套對象依然是代理:
const?proxy?=?reactive({})
const?raw?=?{}
proxy.nested?=?raw
console.log(proxy.nested?===?raw)?//?false
reactive() 的局限性
-
有限的值類型:它只能用于對象類型 (對象、數(shù)組和如 Map、Set 這樣的集合類型)。它不能持有如 string、number 或 boolean 這樣的原始類型。
-
不能替換整個對象:由于 Vue 的響應(yīng)式跟蹤是通過屬性訪問實(shí)現(xiàn)的,因此我們必須始終保持對響應(yīng)式對象的相同引用。這意味著我們不能輕易地“替換”響應(yīng)式對象,因?yàn)檫@樣的話與第一個引用的響應(yīng)性連接將丟失:
let?state?=?reactive({?count:?0?})
//?上面的?({?count:?0?})?引用將不再被追蹤
//?(響應(yīng)性連接已丟失!)
state?=?reactive({?count:?1?})
-
對解構(gòu)操作不友好:當(dāng)我們將響應(yīng)式對象的原始類型屬性解構(gòu)為本地變量時,或者將該屬性傳遞給函數(shù)時,我們將丟失響應(yīng)性連接:
const?state?=?reactive({?count:?0?})
//?當(dāng)解構(gòu)時,count?已經(jīng)與?state.count?斷開連接
let?{?count?}?=?state
//?不會影響原始的?state
count++
//?該函數(shù)接收到的是一個普通的數(shù)字
//?并且無法追蹤?state.count?的變化
//?我們必須傳入整個對象以保持響應(yīng)性
callSomeFunction(state.count)
由于這些限制,我們建議使用 ref() 作為聲明響應(yīng)式狀態(tài)的主要 API。
額外的 ref 解包細(xì)節(jié)
-
作為 reactive 對象的屬性 一個 ref 會在作為響應(yīng)式對象的屬性被訪問或修改時自動解包。換句話說,它的行為就像一個普通的屬性:
const?count?=?ref(0)
const?state?=?reactive({
??count
})
console.log(state.count)?//?0
state.count?=?1
console.log(count.value)?//?1
-
如果將一個新的 ref 賦值給一個關(guān)聯(lián)了已有 ref 的屬性,那么它會替換掉舊的 ref:
const?otherCount?=?ref(2)
state.count?=?otherCount
console.log(state.count)?//?2
//?原始?ref?現(xiàn)在已經(jīng)和?state.count?失去聯(lián)系
console.log(count.value)?//?1
只有當(dāng)嵌套在一個深層響應(yīng)式對象內(nèi)時,才會發(fā)生 ref 解包。當(dāng)其作為淺層響應(yīng)式對象的屬性被訪問時不會解包。
數(shù)組和集合的注意事項(xiàng)
與 reactive 對象不同的是,當(dāng) ref 作為響應(yīng)式數(shù)組或原生集合類型(如 Map) 中的元素被訪問時,它不會被解包:
const?books?=?reactive([ref('Vue?3?Guide')])
//?這里需要?.value
console.log(books[0].value)
const?map?=?reactive(new?Map([['count',?ref(0)]]))
//?這里需要?.value?訪問
console.log(map.get('count').value)//輸出0
new?Map([['count',?ref(0)]]?這個理解起來就是
訪問?key為count的對應(yīng)value值?
也就是一組鍵值對的結(jié)構(gòu),具有極快的查找速度。
ref自動解包就是無需加上.value訪問,比如在模版中使用會自動解包{{msg}}
不會自動解包 就是需要再后面加上一個.value才能訪問到值文章來源:http://www.zghlxwxcb.cn/news/detail-794119.html
Map是ES6規(guī)范引入新的數(shù)據(jù)類型。文章來源地址http://www.zghlxwxcb.cn/news/detail-794119.html
到了這里,關(guān)于vue3-響應(yīng)式基礎(chǔ)之reactive的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!