自拍偷在线精品自拍偷|国产无码一区二区久久|最新版天堂资源中文官网|国产精品第一页爽爽影院|国产精品一区二区av不卡|久久久波多野av一区无码|国产欧美日本亚洲精品一4区|亚洲精品天堂在线观看2020

當(dāng)前位置:首頁 > 軟件開放 > 正文內(nèi)容

vue3響應(yīng)式(vue3響應(yīng)式原理)

軟件開放2年前 (2023-02-28)1337

今天給各位分享vue3響應(yīng)式的知識,其中也會對vue3響應(yīng)式原理進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧!

本文目錄一覽:

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):核心就一個(gè)數(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)的呢?

與其空談原理,不如讓我們來手寫一個(gè)簡易版吧。

響應(yīng)式

首先,什么是響應(yīng)式呢?

響應(yīng)式就是被觀察的數(shù)據(jù)變化的時(shí)候做一系列聯(lián)動處理。

就像一個(gè) 社會 熱點(diǎn)事件,當(dāng)它有消息更新的時(shí)候,各方媒體都會跟進(jìn)做相關(guān)報(bào)道。

這里 社會 熱點(diǎn)事件就是被觀察的目標(biāo)。

那在前端框架里,這個(gè)被觀察的目標(biāo)是什么呢?

很明顯,是狀態(tài)。

狀態(tài)一般是多個(gè),會通過對象的方式來組織。所以,我們觀察狀態(tài)對象的每個(gè) key 的變化,聯(lián)動做一系列處理就可以了。

我們要維護(hù)這樣的數(shù)據(jù)結(jié)構(gòu):

圖片

狀態(tài)對象的每個(gè) key 都有關(guān)聯(lián)的一系列 effect 副作用函數(shù),也就是變化的時(shí)候聯(lián)動執(zhí)行的邏輯,通過 Set 來組織。

每個(gè) key 都是這樣關(guān)聯(lián)了一系列 effect 函數(shù),那多個(gè) key 就可以放到一個(gè) Map 里維護(hù)。

這個(gè) Map 是在對象存在的時(shí)候它就存在,對象銷毀的時(shí)候它也要跟著銷毀。(因?yàn)閷ο蠖紱]了自然也不需要維護(hù)每個(gè) key 關(guān)聯(lián)的 effect 了)

而 WeakMap 正好就有這樣的特性,WeakMap 的 key 必須是一個(gè)對象,value 可以是任意數(shù)據(jù),key 的對象銷毀的時(shí)候,value 也會銷毀。

所以,響應(yīng)式的 Map 會用 WeakMap 來保存,key 為原對象。

這個(gè)數(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)就是圖中的那個(gè):

圖片

圖片

然后添加 deps 依賴,比如一個(gè)函數(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)值的時(shí)候,就建立了和該狀態(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 的時(shí)候,就會觸發(fā) get,會拿到對象的響應(yīng)式的 Map,從里面取出 a 對應(yīng)的 deps 集合,往里面添加當(dāng)前的 effect 函數(shù)。

這樣就完成了一次依賴收集。

當(dāng)你修改 obj.a 的時(shí)候,要通知所有的 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 來收集依賴,這時(shí)候打印的 obj.a 是 1

然后當(dāng) obj.a 賦值為 3 后,會觸發(fā) set,執(zhí)行收集的依賴,這時(shí)候打印 obj.a 是 3

依賴也正確收集到了:

圖片

結(jié)果是對的,我們完成了基本的響應(yīng)式!

當(dāng)然,響應(yīng)式不會只有這么點(diǎn)代碼的,我們現(xiàn)在的實(shí)現(xiàn)還不完善,還有一些問題。

比如,如果代碼里有分支切換,上次執(zhí)行會依賴 obj.b 下次執(zhí)行又不依賴了,這時(shí)候是不是就有了無效的依賴?

這樣一段代碼:

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,這時(shí)候會走到第一個(gè)分支,又依賴了 obj.b。

把 obj.a 修改為 undefined,觸發(fā) set,執(zhí)行所有的依賴函數(shù),這時(shí)候走到分支二,不再依賴 obj.b。

把 obj.b 修改為 3,按理說這時(shí)候沒有依賴 b 的函數(shù)了,我們執(zhí)行試一下:

圖片

第一次打印 2 是對的,也就是走到了第一個(gè)分支,打印 obj.b

第二次打印 nothing 也是對的,這時(shí)候走到第二個(gè)分支。

但是第三次打印 nothing 就不對了,因?yàn)檫@時(shí)候 obj.b 已經(jīng)沒有依賴函數(shù)了,但是還是打印了。

打印看下 deps,會發(fā)現(xiàn) obj.b 的 deps 沒有清除

圖片

所以解決方案就是每次添加依賴前清空下上次的 deps。

怎么清空某個(gè)函數(shù)關(guān)聯(lián)的所有 deps 呢?

記錄下就好了。

我們改造下現(xiàn)有的 effect 函數(shù):

let activeEffect

function effect(fn) {

activeEffect = fn

fn()

}

記錄下這個(gè) effect 函數(shù)被放到了哪些 deps 集合里。也就是:

let activeEffect

function effect(fn) {

const effectFn = () = {

activeEffect = effectFn

fn()

}

effectFn.deps = []

effectFn()

}

對之前的 fn 包一層,在函數(shù)上添加個(gè) deps 數(shù)組來記錄被添加到哪些依賴集合里。

get 收集依賴的時(shí)候,也記錄一份到這里:

圖片

這樣下次再執(zhí)行這個(gè) effect 函數(shù)的時(shí)候,就可以把這個(gè) 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 的時(shí)候會執(zhí)行所有的當(dāng)前 key 的 deps 集合里的 effect 函數(shù)。

而我們執(zhí)行 effect 函數(shù)之前會把它從之前的 deps 集合中清掉:

圖片

執(zhí)行的時(shí)候又被添加到了 deps 集合。

這樣 delete 又 add,delete 又 add,所以就無限循環(huán)了。

解決的方式就是創(chuàng)建第二個(gè) 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)是完善的了么?

也不是,還有一個(gè)問題:

如果 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 的時(shí)候,會把它賦值給一個(gè)全局變量 activeEffect,然后后面收集依賴就用的這個(gè)。

當(dāng)嵌套 effect 的時(shí)候,內(nèi)層函數(shù)執(zhí)行后會修改 activeEffect 這樣收集到的依賴就不對了。

怎么辦呢?

嵌套的話加一個(gè)棧來記錄 effect 不就行了?

也就是這樣:

圖片

執(zhí)行 effect 函數(shù)前把當(dāng)前 effectFn 入棧,執(zhí)行完以后出棧,修改 activeEffect 為棧頂?shù)?effectFn。

這樣就保證了收集到的依賴是正確的。

這種思想的應(yīng)用還是很多的,需要保存和恢復(fù)上下文的時(shí)候,都是這樣加一個(gè)棧。

我們再測試一下:

圖片

現(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ù)變化的時(shí)候做一系列聯(lián)動的處理。

核心是這樣一個(gè)數(shù)據(jù)結(jié)構(gòu):

圖片

最外層是 WeakMap,key 為對象,value 為響應(yīng)式的 Map。這樣當(dāng)對象銷毀時(shí),Map 也會銷毀。

Map 里保存了每個(gè) key 的依賴集合,用 Set 組織。

我們通過 Proxy 來完成自動的依賴收集,也就是添加 effect 到對應(yīng) key 的 deps 的集合里。set 的時(shí)候觸發(fā)所有的 effect 函數(shù)執(zhí)行。

這就是基本的響應(yīng)式系統(tǒng)。

但是還不夠完善,每次執(zhí)行 effect 前要從上次添加到的 deps 集合中刪掉它,然后重新收集依賴。這樣可以避免因?yàn)榉种袚Q產(chǎn)生的無效依賴。

并且執(zhí)行 deps 中的 effect 前要創(chuàng)建一個(gè)新的 Set 來執(zhí)行,避免 add、delete 循環(huán)起來。

此外,為了支持嵌套 effect,需要在執(zhí)行 effect 之前把它推到棧里,然后執(zhí)行完出棧。

解決了這幾個(gè)問題之后,就是一個(gè)完善的 Vue 響應(yīng)式系統(tǒng)了。

當(dāng)然,現(xiàn)在雖然功能是完善的,但是沒有實(shí)現(xiàn) computed、watch 等功能,之后再實(shí)現(xiàn)。

最后,再來看一下這個(gè)數(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做的這個(gè)事情

? ? 經(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是一個(gè)對象,則會遞歸reactive。為什么要遞歸處理呢?proxy不是已經(jīng)把整個(gè)對象都代理到了嗎?

? ? 寫一個(gè)例子看一下

? ? ? ? 如果正常訪問,我沒有問題的,每次都可以正確的觸發(fā)get

? ? ? ? 如果是拿到返回值再進(jìn)行訪問的話,res.c就是無效的

? ? ????把第二個(gè)值也轉(zhuǎn)為Proxy后就可以了

? ? 回到正題,進(jìn)入track函數(shù)

? ? 在trackEffects中完成依賴收集

? ? 同樣的,當(dāng)set newValue時(shí)將執(zhí)行到createSetter。這將執(zhí)行trigger進(jìn)行更新派發(fā)

總結(jié)

? ? 拿到options的data--視情況(如對象遞歸執(zhí)行)進(jìn)行reactive化--在訪問時(shí)收集依賴(ReactiveEffect)--設(shè)置值時(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)有一段時(shí)間了,真可謂是千呼萬喚始出來啊!

相比于 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 的缺陷,同時(shí)也帶來了性能上的提升。

今天,我們就來盤一盤它,看看 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 - 代理,顧名思義,就是在要訪問的對象之前增加一個(gè)中間層,這樣就不直接訪問對象,而是通過中間層做一個(gè)中轉(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)出一個(gè) reactive 方法,該方法有一個(gè)參數(shù) target ,目的就是將 target 變成響應(yīng)式對象,因此返回值就是一個(gè)響應(yīng)式對象。

reactive 方法基本結(jié)構(gòu)就是如此,給定一個(gè)對象,返回一個(gè)響應(yīng)式對象。

其中 isObject 方法用于判斷是否是對象,不是對象不需要代理,直接返回即可。

reactive 方法的重點(diǎn)是 Proxy 的第二個(gè)參數(shù) handler ,它承載監(jiān)控對象變化,依賴收集,視圖更新等各項(xiàng)重大責(zé)任,我們重點(diǎn)來研究這個(gè)對象。

handler.js

在 Vue3 中 Proxy 的 handler 主要設(shè)置了 get , set , deleteProperty , has , ownKeys 這些屬性,即攔截了對象的讀取,設(shè)置,刪除, in 以及 Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法。

這里我們偷個(gè)懶,暫時(shí)就考慮 set 和 get 操作。

handler.get()

get 獲取屬性比較簡單,我們先來看看這個(gè),這里我們用一個(gè)方法創(chuàng)建 getHanlder 。

這里推薦使用了 Reflect.get 而并非 target[key] 。

可以發(fā)現(xiàn), Vue3 是在取值的時(shí)候才去遞歸遍歷屬性的,而非 Vue2 中一開始就遞歸 data 給每個(gè)屬性添加 Watcher ,這也是 Vue3 性能提升之一。

handler.set()

同理 set 操作,我們也是用一個(gè)方法創(chuàng)建 setHandler 。

Reflect.set 會返回一個(gè) Boolean 值,用于判斷屬性是否設(shè)置成功。

完事后將 handler 導(dǎo)出,然后在 reactive 中引入即可。

測試幾組對象貌似沒啥問題,其實(shí)是有一個(gè)坑,這個(gè)坑也跟數(shù)組有關(guān)。

如上例子,如果我們選擇代理數(shù)組,在 setHandler 中打印其 key 和 value 的話會得到 3 4 , length 4 這兩組值:

如果不作處理,那么會導(dǎo)致如果更新視圖的話,則會觸發(fā)兩次,這肯定是不允許的,因此,我們需要將區(qū)分新增和修改這兩種操作。

Vue3 中是通過判斷 target 是否存在該屬性來區(qū)分是新增還是修改操作,需要借助一個(gè)工具方法 —— hasOwnProperty 。

這里我們將上述的 createSetter 方法修改如下:

如此一來,我們調(diào) push 方法的時(shí)候,就只會觸發(fā)一次更新了,非常巧妙的避免了無意義的更新操作。

effect.js

光上述構(gòu)造響應(yīng)式對象并不能完成響應(yīng)式的操作,我們還需要一個(gè)非常重要的方法 effect ,它會在初始化執(zhí)行的時(shí)候存儲跟其有關(guān)的數(shù)據(jù)依賴,當(dāng)依賴數(shù)據(jù)發(fā)生變化的時(shí)候,則會再次觸發(fā) effect 傳遞的函數(shù)。

其基本雛形如下,入?yún)⑹且粋€(gè)函數(shù),還有個(gè)可選參數(shù) options 方便后面計(jì)算屬性等使用,暫時(shí)不考慮:

createReactiveEffect 就是為了將 fn 變成響應(yīng)式函數(shù),監(jiān)控?cái)?shù)據(jù)變化,執(zhí)行 fn 函數(shù),因此該函數(shù)是一個(gè)高階函數(shù)。

createReactiveEffect 將原來的 fn 轉(zhuǎn)變成一個(gè) reactvieEffect , 并將當(dāng)前的 effect 掛到全局的 activeEffect 上,目的是為了一會與當(dāng)前所依賴的屬性做好對應(yīng)關(guān)系。

我們必須要將依賴屬性構(gòu)造成 { prop : [effect,effect] } 這種結(jié)構(gòu),才能保證依賴屬性變化的時(shí)候,依次去觸發(fā)與之相關(guān)的 effect ,因此,需要在 get 屬性的時(shí)候,做屬性的依賴收集,將屬性與 effect 關(guān)聯(lián)起來。

依賴收集 —— track

在獲取對象的屬性時(shí),會觸發(fā) getHandler ,再次做屬性的依賴收集,即 Vue2 中的發(fā)布訂閱。

在 setHandler 中獲取屬性的時(shí)候,做一次 track(target, key) 操作。

整個(gè) 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ù)的時(shí)候通過 track 進(jìn)行依賴收集,更新數(shù)據(jù)的時(shí)候再通過 trigger 進(jìn)行更新,就完成了整個(gè)數(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)式的介紹就聊到這里吧,感謝你花時(shí)間閱讀本站內(nèi)容,更多關(guān)于vue3響應(yīng)式原理、vue3響應(yīng)式的信息別忘了在本站進(jìn)行查找喔。

掃描二維碼推送至手機(jī)訪問。

版權(quán)聲明:本文由飛速云SEO網(wǎng)絡(luò)優(yōu)化推廣發(fā)布,如需轉(zhuǎn)載請注明出處。

本文鏈接:http://www.thonggone.com/post/10359.html

標(biāo)簽: vue3響應(yīng)式js

“vue3響應(yīng)式(vue3響應(yīng)式原理)” 的相關(guān)文章

eclipse怎么看項(xiàng)目位置(eclipse怎么看文件位置)

eclipse怎么看項(xiàng)目位置(eclipse怎么看文件位置)

今天給各位分享eclipse怎么看項(xiàng)目位置的知識,其中也會對eclipse怎么看文件位置進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧!本文目錄一覽: 1、導(dǎo)入的項(xiàng)目存放的位置在哪里 eclipse 2、怎么在eclipse中調(diào)試查看項(xiàng)目的運(yùn)行流程 3、eclipse項(xiàng)...

手機(jī)怎么創(chuàng)建html文件(手機(jī)上如何編寫html)

手機(jī)怎么創(chuàng)建html文件(手機(jī)上如何編寫html)

本篇文章給大家談?wù)勈謾C(jī)怎么創(chuàng)建html文件,以及手機(jī)上如何編寫html對應(yīng)的知識點(diǎn),希望對各位有所幫助,不要忘了收藏本站喔。 本文目錄一覽: 1、手機(jī)有沒有可能制作html格式文件 2、手機(jī)怎么打開html文件 3、html文件在安卓手機(jī)上怎么打開? 4、智能手機(jī)怎么創(chuàng)建.html文件...

個(gè)人簡歷網(wǎng)頁設(shè)計(jì)思路(個(gè)人簡歷頁面設(shè)計(jì))

個(gè)人簡歷網(wǎng)頁設(shè)計(jì)思路(個(gè)人簡歷頁面設(shè)計(jì))

今天給各位分享個(gè)人簡歷網(wǎng)頁設(shè)計(jì)思路的知識,其中也會對個(gè)人簡歷頁面設(shè)計(jì)進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧!本文目錄一覽: 1、Html網(wǎng)頁簡歷如何制作 2、網(wǎng)上求職簡歷制作技巧 3、求DreamWeaver網(wǎng)頁的形式制作一份個(gè)人簡歷 4、如何制作比較炫酷的...

csgo武器皮膚交易平臺app(csgo皮膚交易網(wǎng))

csgo武器皮膚交易平臺app(csgo皮膚交易網(wǎng))

今天給各位分享csgo武器皮膚交易平臺app的知識,其中也會對csgo皮膚交易網(wǎng)進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧!本文目錄一覽: 1、csgo賣皮膚去哪個(gè)平臺 2、csgo買皮膚去哪個(gè)平臺? 3、csgo買皮膚去哪個(gè)平臺 csgo賣皮膚去哪個(gè)平臺 Igx...

怎樣畫漫畫少女的圖片(怎樣畫漫畫少女的圖片大全)

怎樣畫漫畫少女的圖片(怎樣畫漫畫少女的圖片大全)

今天給各位分享怎樣畫漫畫少女的圖片的知識,其中也會對怎樣畫漫畫少女的圖片大全進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧!本文目錄一覽: 1、少女怎么畫動漫人物 2、如何畫漫畫少女 3、怎么畫漫畫少女 4、卡通人物簡筆畫美少女怎么畫? 少女怎么畫動漫人物 少女動...

尋寶天行完美世界交易平臺手機(jī)游戲(尋寶天行完美世界站)

尋寶天行完美世界交易平臺手機(jī)游戲(尋寶天行完美世界站)

今天給各位分享尋寶天行完美世界交易平臺手機(jī)游戲的知識,其中也會對尋寶天行完美世界站進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧!本文目錄一覽: 1、尋寶天行購買完美世界國際板游戲角色問題 2、關(guān)于完美世界國際版尋寶網(wǎng)角色交易的問題、 3、完美世界國際版尋寶網(wǎng)天行購買角...