vue3響應(yīng)式(vue3響應(yīng)式原理)
今天給各位分享vue3響應(yīng)式的知識,其中也會對vue3響應(yīng)式原理進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧!
本文目錄一覽:
- 1、vue3響應(yīng)式數(shù)據(jù)原理
- 2、手寫 Vue3 響應(yīng)式系統(tǒng):核心就一個數(shù)據(jù)結(jié)構(gòu)
- 3、vue3源碼解讀--data響應(yīng)式的處理
- 4、聊一聊 Vue3 中響應(yīng)式原理
vue3響應(yīng)式數(shù)據(jù)原理
Effect 原理解析 與 實(shí)現(xiàn)
引言:
vue、react 框架的核心都是數(shù)據(jù)驅(qū)動視圖也就是model = view,實(shí)現(xiàn)的核心也就是 數(shù)據(jù)響應(yīng)。
主要就三步:
一、effect:副作用函數(shù)
1.類似于vue2.0中watch 的升級版,如果函數(shù)中用到的響應(yīng)式的數(shù)據(jù)發(fā)生了變化,則會執(zhí)行該函數(shù)
二、proxy 與reflect
Object.defineProperty API 的一些缺點(diǎn):
vue3源碼的調(diào)試方法:
三、響應(yīng)式api reactive的實(shí)現(xiàn)
三、Effect的依賴收集與響應(yīng)觸發(fā) (分-總-分-問題)
手寫 Vue3 響應(yīng)式系統(tǒng):核心就一個數(shù)據(jù)結(jié)構(gòu)
響應(yīng)式是 Vue 的特色,如果你簡歷里寫了 Vue 項(xiàng)目,那基本都會問響應(yīng)式實(shí)現(xiàn)原理。
而且不只是 Vue,狀態(tài)管理庫 Mobx 也是基于響應(yīng)式實(shí)現(xiàn)的。
那響應(yīng)式是具體怎么實(shí)現(xiàn)的呢?
與其空談原理,不如讓我們來手寫一個簡易版吧。
響應(yīng)式
首先,什么是響應(yīng)式呢?
響應(yīng)式就是被觀察的數(shù)據(jù)變化的時候做一系列聯(lián)動處理。
就像一個 社會 熱點(diǎn)事件,當(dāng)它有消息更新的時候,各方媒體都會跟進(jìn)做相關(guān)報(bào)道。
這里 社會 熱點(diǎn)事件就是被觀察的目標(biāo)。
那在前端框架里,這個被觀察的目標(biāo)是什么呢?
很明顯,是狀態(tài)。
狀態(tài)一般是多個,會通過對象的方式來組織。所以,我們觀察狀態(tài)對象的每個 key 的變化,聯(lián)動做一系列處理就可以了。
我們要維護(hù)這樣的數(shù)據(jù)結(jié)構(gòu):
圖片
狀態(tài)對象的每個 key 都有關(guān)聯(lián)的一系列 effect 副作用函數(shù),也就是變化的時候聯(lián)動執(zhí)行的邏輯,通過 Set 來組織。
每個 key 都是這樣關(guān)聯(lián)了一系列 effect 函數(shù),那多個 key 就可以放到一個 Map 里維護(hù)。
這個 Map 是在對象存在的時候它就存在,對象銷毀的時候它也要跟著銷毀。(因?yàn)閷ο蠖紱]了自然也不需要維護(hù)每個 key 關(guān)聯(lián)的 effect 了)
而 WeakMap 正好就有這樣的特性,WeakMap 的 key 必須是一個對象,value 可以是任意數(shù)據(jù),key 的對象銷毀的時候,value 也會銷毀。
所以,響應(yīng)式的 Map 會用 WeakMap 來保存,key 為原對象。
這個數(shù)據(jù)結(jié)構(gòu)就是響應(yīng)式的核心數(shù)據(jù)結(jié)構(gòu)了。
比如這樣的狀態(tài)對象:
const obj = {
a: 1,
b: 2
}
它的響應(yīng)式數(shù)據(jù)結(jié)構(gòu)就是這樣的:
const depsMap = new Map();
const aDeps = new Set();
depsMap.set('a', aDeps);
const bDeps = new Set();
depsMap.set('b', bDeps);
const reactiveMap = new WeakMap()
reactiveMap.set(obj, depsMap);
創(chuàng)建出的數(shù)據(jù)結(jié)構(gòu)就是圖中的那個:
圖片
圖片
然后添加 deps 依賴,比如一個函數(shù)依賴了 a,那就要添加到 a 的 deps 集合里:
effect(() = {
console.log(obj.a);
});
也就是這樣:
const depsMap = reactiveMap.get(obj);
const aDeps = depsMap.get('a');
aDeps.add(該函數(shù));
這樣維護(hù) deps 功能上沒啥問題,但是難道要讓用戶手動添加 deps 么?
那不但會侵入業(yè)務(wù)代碼,而且還容易遺漏。
所以肯定不會讓用戶手動維護(hù) deps,而是要做自動的依賴收集。
那怎么自動收集依賴呢?
讀取狀態(tài)值的時候,就建立了和該狀態(tài)的依賴關(guān)系,所以很容易想到可以代理狀態(tài)的 get 來實(shí)現(xiàn)。
通過 Object.defineProperty 或者 Proxy 都可以:
const data = {
a: 1,
b: 2
}
let activeEffect
function effect(fn) {
activeEffect = fn
fn()
}
const reactiveMap = new WeakMap()
const obj = new Proxy(data, {
get(targetObj, key) {
let depsMap = reactiveMap.get(targetObj);
if (!depsMap) {
reactiveMap.set(targetObj, (depsMap = new Map()))
}
let deps = depsMap.get(key)
if (!deps) {
depsMap.set(key, (deps = new Set()))
}
deps.add(activeEffect)
return targetObj[key]
}
})
effect 會執(zhí)行傳入的回調(diào)函數(shù) fn,當(dāng)你在 fn 里讀取 obj.a 的時候,就會觸發(fā) get,會拿到對象的響應(yīng)式的 Map,從里面取出 a 對應(yīng)的 deps 集合,往里面添加當(dāng)前的 effect 函數(shù)。
這樣就完成了一次依賴收集。
當(dāng)你修改 obj.a 的時候,要通知所有的 deps,所以還要代理 set:
set(targetObj, key, newVal) {
targetObj[key] = newVal
const depsMap = reactiveMap.get(targetObj)
if (!depsMap) return
const effects = depsMap.get(key)
effects effects.forEach(fn = fn())
}
基本的響應(yīng)式完成了,我們測試一下:
圖片
打印了兩次,第一次是 1,第二次是 3。
effect 會先執(zhí)行一次傳入的回調(diào)函數(shù),觸發(fā) get 來收集依賴,這時候打印的 obj.a 是 1
然后當(dāng) obj.a 賦值為 3 后,會觸發(fā) set,執(zhí)行收集的依賴,這時候打印 obj.a 是 3
依賴也正確收集到了:
圖片
結(jié)果是對的,我們完成了基本的響應(yīng)式!
當(dāng)然,響應(yīng)式不會只有這么點(diǎn)代碼的,我們現(xiàn)在的實(shí)現(xiàn)還不完善,還有一些問題。
比如,如果代碼里有分支切換,上次執(zhí)行會依賴 obj.b 下次執(zhí)行又不依賴了,這時候是不是就有了無效的依賴?
這樣一段代碼:
const obj = {
a: 1,
b: 2
}
effect(() = {
console.log(obj.a ? obj.b : 'nothing');
});
obj.a = undefined;
obj.b = 3;
第一次執(zhí)行 effect 函數(shù),obj.a 是 1,這時候會走到第一個分支,又依賴了 obj.b。
把 obj.a 修改為 undefined,觸發(fā) set,執(zhí)行所有的依賴函數(shù),這時候走到分支二,不再依賴 obj.b。
把 obj.b 修改為 3,按理說這時候沒有依賴 b 的函數(shù)了,我們執(zhí)行試一下:
圖片
第一次打印 2 是對的,也就是走到了第一個分支,打印 obj.b
第二次打印 nothing 也是對的,這時候走到第二個分支。
但是第三次打印 nothing 就不對了,因?yàn)檫@時候 obj.b 已經(jīng)沒有依賴函數(shù)了,但是還是打印了。
打印看下 deps,會發(fā)現(xiàn) obj.b 的 deps 沒有清除
圖片
所以解決方案就是每次添加依賴前清空下上次的 deps。
怎么清空某個函數(shù)關(guān)聯(lián)的所有 deps 呢?
記錄下就好了。
我們改造下現(xiàn)有的 effect 函數(shù):
let activeEffect
function effect(fn) {
activeEffect = fn
fn()
}
記錄下這個 effect 函數(shù)被放到了哪些 deps 集合里。也就是:
let activeEffect
function effect(fn) {
const effectFn = () = {
activeEffect = effectFn
fn()
}
effectFn.deps = []
effectFn()
}
對之前的 fn 包一層,在函數(shù)上添加個 deps 數(shù)組來記錄被添加到哪些依賴集合里。
get 收集依賴的時候,也記錄一份到這里:
圖片
這樣下次再執(zhí)行這個 effect 函數(shù)的時候,就可以把這個 effect 函數(shù)從上次添加到的依賴集合里刪掉:
圖片
cleanup 實(shí)現(xiàn)如下:
function cleanup(effectFn) {
for (let i = 0; i effectFn.deps.length; i++) {
const deps = effectFn.deps[i]
deps.delete(effectFn)
}
effectFn.deps.length = 0
}
effectFn.deps 數(shù)組記錄了被添加到的 deps 集合,從中刪掉自己。
全刪完之后就把上次記錄的 deps 數(shù)組置空。
我們再來測試下:
圖片
無限循環(huán)打印了,什么鬼?
問題出現(xiàn)在這里:
圖片
set 的時候會執(zhí)行所有的當(dāng)前 key 的 deps 集合里的 effect 函數(shù)。
而我們執(zhí)行 effect 函數(shù)之前會把它從之前的 deps 集合中清掉:
圖片
執(zhí)行的時候又被添加到了 deps 集合。
這樣 delete 又 add,delete 又 add,所以就無限循環(huán)了。
解決的方式就是創(chuàng)建第二個 Set,只用于遍歷:
圖片
這樣就不會無限循環(huán)了。
再測試一次:
圖片
現(xiàn)在當(dāng) obj.a 賦值為 undefined 之后,再次執(zhí)行 effect 函數(shù),obj.b 的 deps 集合就被清空了,所以需改 obj.b 也不會打印啥。
看下現(xiàn)在的響應(yīng)式數(shù)據(jù)結(jié)構(gòu):
圖片
確實(shí),b 的 deps 集合被清空了。
那現(xiàn)在的響應(yīng)式實(shí)現(xiàn)是完善的了么?
也不是,還有一個問題:
如果 effect 嵌套了,那依賴還能正確的收集么?
首先講下為什么要支持 effect 嵌套,因?yàn)榻M件是可以嵌套的,而且組件里會寫 effect,那也就是 effect 嵌套了,所以必須支持嵌套。
我們嵌套下試試:
effect(() = {
console.log('effect1');
effect(() = {
console.log('effect2');
obj.b;
});
obj.a;
});
obj.a = 3;
按理說會打印一次 effect1、一次 effect2,這是最開始的那次執(zhí)行。
然后 obj.a 修改為 3 后,會觸發(fā)一次 effect1 的打印,執(zhí)行內(nèi)層 effect,又觸發(fā)一次 effect2 的打印。
也就是會打印 effect1、effect2、effect1、effect2。
我們測試下:
圖片
打印了 effect1、effet2 這是對的,但第三次打印的是 effect2,這說明 obj.a 修改后并沒有執(zhí)行外層函數(shù),而是執(zhí)行的內(nèi)層函數(shù)。
為什么呢?
看下這段代碼:
圖片
我們執(zhí)行 effect 的時候,會把它賦值給一個全局變量 activeEffect,然后后面收集依賴就用的這個。
當(dāng)嵌套 effect 的時候,內(nèi)層函數(shù)執(zhí)行后會修改 activeEffect 這樣收集到的依賴就不對了。
怎么辦呢?
嵌套的話加一個棧來記錄 effect 不就行了?
也就是這樣:
圖片
執(zhí)行 effect 函數(shù)前把當(dāng)前 effectFn 入棧,執(zhí)行完以后出棧,修改 activeEffect 為棧頂?shù)?effectFn。
這樣就保證了收集到的依賴是正確的。
這種思想的應(yīng)用還是很多的,需要保存和恢復(fù)上下文的時候,都是這樣加一個棧。
我們再測試一下:
圖片
現(xiàn)在的打印就對了。
至此,我們的響應(yīng)式系統(tǒng)就算比較完善了。
全部代碼如下:
const data = {
a: 1,
b: 2
}
let activeEffect
const effectStack = [];
function effect(fn) {
const effectFn = () = {
cleanup(effectFn)
activeEffect = effectFn
effectStack.push(effectFn);
fn()
effectStack.pop();
activeEffect = effectStack[effectStack.length - 1];
}
effectFn.deps = []
effectFn()
}
function cleanup(effectFn) {
for (let i = 0; i effectFn.deps.length; i++) {
const deps = effectFn.deps[i]
deps.delete(effectFn)
}
effectFn.deps.length = 0
}
const reactiveMap = new WeakMap()
const obj = new Proxy(data, {
get(targetObj, key) {
let depsMap = reactiveMap.get(targetObj)
if (!depsMap) {
reactiveMap.set(targetObj, (depsMap = new Map()))
}
let deps = depsMap.get(key)
if (!deps) {
depsMap.set(key, (deps = new Set()))
}
deps.add(activeEffect)
activeEffect.deps.push(deps);
return targetObj[key]
},
set(targetObj, key, newVal) {
targetObj[key] = newVal
const depsMap = reactiveMap.get(targetObj)
if (!depsMap) return
const effects = depsMap.get(key)
// effects effects.forEach(fn = fn())
const effectsToRun = new Set(effects);
effectsToRun.forEach(effectFn = effectFn());
}
})
總結(jié)
響應(yīng)式就是數(shù)據(jù)變化的時候做一系列聯(lián)動的處理。
核心是這樣一個數(shù)據(jù)結(jié)構(gòu):
圖片
最外層是 WeakMap,key 為對象,value 為響應(yīng)式的 Map。這樣當(dāng)對象銷毀時,Map 也會銷毀。
Map 里保存了每個 key 的依賴集合,用 Set 組織。
我們通過 Proxy 來完成自動的依賴收集,也就是添加 effect 到對應(yīng) key 的 deps 的集合里。set 的時候觸發(fā)所有的 effect 函數(shù)執(zhí)行。
這就是基本的響應(yīng)式系統(tǒng)。
但是還不夠完善,每次執(zhí)行 effect 前要從上次添加到的 deps 集合中刪掉它,然后重新收集依賴。這樣可以避免因?yàn)榉种袚Q產(chǎn)生的無效依賴。
并且執(zhí)行 deps 中的 effect 前要創(chuàng)建一個新的 Set 來執(zhí)行,避免 add、delete 循環(huán)起來。
此外,為了支持嵌套 effect,需要在執(zhí)行 effect 之前把它推到棧里,然后執(zhí)行完出棧。
解決了這幾個問題之后,就是一個完善的 Vue 響應(yīng)式系統(tǒng)了。
當(dāng)然,現(xiàn)在雖然功能是完善的,但是沒有實(shí)現(xiàn) computed、watch 等功能,之后再實(shí)現(xiàn)。
最后,再來看一下這個數(shù)據(jù)結(jié)構(gòu),理解了它就理解了 vue 響應(yīng)式的核心:
圖片
vue3源碼解讀--data響應(yīng)式的處理
目錄
????vue2源碼
????vue3源碼
示例
源碼
? ? 上一節(jié),我們已經(jīng)看到了組件被掛載到頁面的流程。但是忽略了對options的處理。vue2中是在組件init過程中就對配置項(xiàng)進(jìn)行了合并處理,vue3中是在組件創(chuàng)建即setupComponent中執(zhí)行applyOptions做的這個事情
? ? 經(jīng)過對組件實(shí)例的解析操作,最終拿到的dataOptions即我們實(shí)例中的data函數(shù)??梢钥吹?,在vue3已經(jīng)不允許根組件定義為對象了
? ? 顯然reactive即響應(yīng)式實(shí)現(xiàn)的關(guān)鍵,順著調(diào)用關(guān)系找到createReactiveObject函數(shù)。常聽人提起的Proxy赫然立于眼前
? ? proxy和Object.defineProperty差不多,都可以攔截對象的訪問和修改操作,那么接下來的重點(diǎn)就是看下它是如何做依賴收集和派發(fā)更新的即可
? ? 當(dāng)前targetType=1,使用baseHandlers做處理器,即createGetter函數(shù)。當(dāng)組件render過程中將會觸發(fā)msg的訪問執(zhí)行到此
? ? 可以看到,如果msg是一個對象,則會遞歸reactive。為什么要遞歸處理呢?proxy不是已經(jīng)把整個對象都代理到了嗎?
? ? 寫一個例子看一下
? ? ? ? 如果正常訪問,我沒有問題的,每次都可以正確的觸發(fā)get
? ? ? ? 如果是拿到返回值再進(jìn)行訪問的話,res.c就是無效的
? ? ????把第二個值也轉(zhuǎn)為Proxy后就可以了
? ? 回到正題,進(jìn)入track函數(shù)
? ? 在trackEffects中完成依賴收集
? ? 同樣的,當(dāng)set newValue時將執(zhí)行到createSetter。這將執(zhí)行trigger進(jìn)行更新派發(fā)
總結(jié)
? ? 拿到options的data--視情況(如對象遞歸執(zhí)行)進(jìn)行reactive化--在訪問時收集依賴(ReactiveEffect)--設(shè)置值時派發(fā)更新
? ? proxy.x相當(dāng)于讓activeEffect去訂閱data的change,proxy.x = y則相當(dāng)于data發(fā)布更新,通知activeEffect執(zhí)行componentUpdateFn? ? ? ? ? ? ?--觀察者模式
聊一聊 Vue3 中響應(yīng)式原理
Vue.js 3.0 "One Piece" 正式發(fā)布已經(jīng)有一段時間了,真可謂是千呼萬喚始出來?。?/p>
相比于 Vue2.x , Vue3.0 在新的版本中提供了更好的性能、更小的捆綁包體積、更好的 TypeScript 集成、用于處理大規(guī)模用例的新 API 。
在發(fā)布之前,尤大大就已經(jīng)聲明了響應(yīng)式方面將采用 Proxy 對于之前的 Object.defineProperty 進(jìn)行改寫。其主要目的就是彌補(bǔ) Object.defineProperty 自身的一些缺陷,例如無法檢測到對象屬性的新增或者刪除,不能監(jiān)聽數(shù)組的變化等。
而 Vue3 采用了新的 Proxy 實(shí)現(xiàn)數(shù)據(jù)讀取和設(shè)置攔截,不僅彌補(bǔ)了之前 Vue2 中 Object.defineProperty 的缺陷,同時也帶來了性能上的提升。
今天,我們就來盤一盤它,看看 Vue3 中響應(yīng)式是如何實(shí)現(xiàn)的。
The Proxy object enables you to create a proxy for another object, which can intercept and redefine fundamental operations for that object. MDN
Proxy - 代理,顧名思義,就是在要訪問的對象之前增加一個中間層,這樣就不直接訪問對象,而是通過中間層做一個中轉(zhuǎn),通過操作代理對象,來實(shí)現(xiàn)修改目標(biāo)對象。
關(guān)于 Proxy 的更多的知識,可以參考我之前的一篇文章 —— 初探 Vue3.0 中的一大亮點(diǎn)——Proxy ! ,這里我就不在贅述。
Vue3 中響應(yīng)式核心方法就是 reactive 和 effect , 其中 reactive 方法是負(fù)責(zé)將數(shù)據(jù)變成響應(yīng)式, effect 方法的作用是根據(jù)數(shù)據(jù)變化去更新視圖或調(diào)用函數(shù),與 react 中的 useEffect 有點(diǎn)類似~
其大概用法如下:
默認(rèn)會執(zhí)行一次,打印 Hello , 之后更改了 data.name 的值后,會在觸發(fā)執(zhí)行一次,打印 World 。
我們先看看 reactive 方法的實(shí)現(xiàn)~
reactive.js
首先應(yīng)該明確,我們應(yīng)該導(dǎo)出一個 reactive 方法,該方法有一個參數(shù) target ,目的就是將 target 變成響應(yīng)式對象,因此返回值就是一個響應(yīng)式對象。
reactive 方法基本結(jié)構(gòu)就是如此,給定一個對象,返回一個響應(yīng)式對象。
其中 isObject 方法用于判斷是否是對象,不是對象不需要代理,直接返回即可。
reactive 方法的重點(diǎn)是 Proxy 的第二個參數(shù) handler ,它承載監(jiān)控對象變化,依賴收集,視圖更新等各項(xiàng)重大責(zé)任,我們重點(diǎn)來研究這個對象。
handler.js
在 Vue3 中 Proxy 的 handler 主要設(shè)置了 get , set , deleteProperty , has , ownKeys 這些屬性,即攔截了對象的讀取,設(shè)置,刪除, in 以及 Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法。
這里我們偷個懶,暫時就考慮 set 和 get 操作。
handler.get()
get 獲取屬性比較簡單,我們先來看看這個,這里我們用一個方法創(chuàng)建 getHanlder 。
這里推薦使用了 Reflect.get 而并非 target[key] 。
可以發(fā)現(xiàn), Vue3 是在取值的時候才去遞歸遍歷屬性的,而非 Vue2 中一開始就遞歸 data 給每個屬性添加 Watcher ,這也是 Vue3 性能提升之一。
handler.set()
同理 set 操作,我們也是用一個方法創(chuàng)建 setHandler 。
Reflect.set 會返回一個 Boolean 值,用于判斷屬性是否設(shè)置成功。
完事后將 handler 導(dǎo)出,然后在 reactive 中引入即可。
測試幾組對象貌似沒啥問題,其實(shí)是有一個坑,這個坑也跟數(shù)組有關(guān)。
如上例子,如果我們選擇代理數(shù)組,在 setHandler 中打印其 key 和 value 的話會得到 3 4 , length 4 這兩組值:
如果不作處理,那么會導(dǎo)致如果更新視圖的話,則會觸發(fā)兩次,這肯定是不允許的,因此,我們需要將區(qū)分新增和修改這兩種操作。
Vue3 中是通過判斷 target 是否存在該屬性來區(qū)分是新增還是修改操作,需要借助一個工具方法 —— hasOwnProperty 。
這里我們將上述的 createSetter 方法修改如下:
如此一來,我們調(diào) push 方法的時候,就只會觸發(fā)一次更新了,非常巧妙的避免了無意義的更新操作。
effect.js
光上述構(gòu)造響應(yīng)式對象并不能完成響應(yīng)式的操作,我們還需要一個非常重要的方法 effect ,它會在初始化執(zhí)行的時候存儲跟其有關(guān)的數(shù)據(jù)依賴,當(dāng)依賴數(shù)據(jù)發(fā)生變化的時候,則會再次觸發(fā) effect 傳遞的函數(shù)。
其基本雛形如下,入?yún)⑹且粋€函數(shù),還有個可選參數(shù) options 方便后面計(jì)算屬性等使用,暫時不考慮:
createReactiveEffect 就是為了將 fn 變成響應(yīng)式函數(shù),監(jiān)控?cái)?shù)據(jù)變化,執(zhí)行 fn 函數(shù),因此該函數(shù)是一個高階函數(shù)。
createReactiveEffect 將原來的 fn 轉(zhuǎn)變成一個 reactvieEffect , 并將當(dāng)前的 effect 掛到全局的 activeEffect 上,目的是為了一會與當(dāng)前所依賴的屬性做好對應(yīng)關(guān)系。
我們必須要將依賴屬性構(gòu)造成 { prop : [effect,effect] } 這種結(jié)構(gòu),才能保證依賴屬性變化的時候,依次去觸發(fā)與之相關(guān)的 effect ,因此,需要在 get 屬性的時候,做屬性的依賴收集,將屬性與 effect 關(guān)聯(lián)起來。
依賴收集 —— track
在獲取對象的屬性時,會觸發(fā) getHandler ,再次做屬性的依賴收集,即 Vue2 中的發(fā)布訂閱。
在 setHandler 中獲取屬性的時候,做一次 track(target, key) 操作。
整個 track 的數(shù)據(jù)結(jié)構(gòu)大概是這樣
目的就是將 target , key , effect 之間做好對應(yīng)的關(guān)系映射。
打印 targetMap 的結(jié)構(gòu)如下:
**觸發(fā)更新 —— trigger **
上述已經(jīng)完成了依賴收集,剩下就是監(jiān)控?cái)?shù)據(jù)變化,觸發(fā)更新操作,即在 setHandler 中添加 trigger 觸發(fā)操作。
這樣一來,獲取數(shù)據(jù)的時候通過 track 進(jìn)行依賴收集,更新數(shù)據(jù)的時候再通過 trigger 進(jìn)行更新,就完成了整個數(shù)據(jù)的響應(yīng)式操作。
再回頭看看我們先前提到的例子:
控制臺會依次打印 Hello ***** effect ***** 以及 World ***** effect ***** , 分別是首次渲染觸發(fā)跟更新數(shù)據(jù)重渲染觸發(fā),至此功能實(shí)現(xiàn)!
整體來說, Vue3 相比于 Vue2 在很多方面都做了調(diào)整,數(shù)據(jù)的響應(yīng)式只是冰山一角,但是可以看出尤大團(tuán)隊(duì)非常巧妙的利用了 Proxy 的特點(diǎn)以及 es6 的數(shù)據(jù)結(jié)構(gòu)和方法。另外, Composition API 的模式跟 React 在某些程度上有異曲同工之妙,這種設(shè)計(jì)模式讓我們在實(shí)際開發(fā)使用中更加的方法快捷,值得我們?nèi)W(xué)習(xí),加油!
最后附上倉庫地址 github ,歡迎各位大佬批評斧正~
vue3響應(yīng)式的介紹就聊到這里吧,感謝你花時間閱讀本站內(nèi)容,更多關(guān)于vue3響應(yīng)式原理、vue3響應(yīng)式的信息別忘了在本站進(jìn)行查找喔。
掃描二維碼推送至手機(jī)訪問。
版權(quán)聲明:本文由飛速云SEO網(wǎng)絡(luò)優(yōu)化推廣發(fā)布,如需轉(zhuǎn)載請注明出處。