您好,登錄后才能下訂單哦!
這篇文章主要介紹“Vue3的響應式原理是什么”,在日常操作中,相信很多人在Vue3的響應式原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Vue3的響應式原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
Vue3 的響應式原理依賴了 Proxy 這個核心 API,通過 Proxy 可以劫持對象的某些操作。
const obj = { a: 1 }; const p = new Proxy(obj, { get(target, property, receiver) { console.log("get"); return Reflect.get(target, property, receiver); }, set(target, property, value, receiver) { console.log("set"); return Reflect.set(target, property, receiver); }, has(target, prop) { console.log("has"); return Reflect.has(target, prop); }, deleteProperty(target, prop) { console.log("deleteProperty"); return Reflect.deleteProperty(target, prop); }, }); p.a; // 輸出 --> get p.a = 2; // 輸出 --> set "a" in p; // 輸出 --> has delete p.a; // 輸出 --> deleteProperty
如上例子,我們用 Proxy 代理了 Obj 對象的屬性訪問、屬性賦值、in 操作符、delete 的操作,并進行 console.log 輸出。
Reflect 是與 Proxy 搭配使用的一個 API,當我們劫持了某些操作時,如果需要再把這些操作反射回去,那么就需要 Reflect 這個 API。
由于我們攔截了對象的操作,所以這些操作該有的功能都喪失了,例如,訪問屬性 p.a 應該得到 a 屬性的值,但此時卻不會有任何結果,如果我們還想擁有攔截之前的功能,那我們就需要用 Reflect 反射回去。
const obj = { a: 1 }; const p = new Proxy(obj, { get(target, property, receiver) { console.log("get"); return Reflect.get(target, property, receiver); }, set(target, property, value, receiver) { console.log("set"); return Reflect.set(target, property, receiver); }, has(target, prop) { console.log("has"); return Reflect.has(target, prop); }, deleteProperty(target, prop) { console.log("deleteProperty"); return Reflect.deleteProperty(target, prop); }, });
以下全文我們都會通過這個例子來講述 Vue3 響應式的原理。
<div id="app"></div> <script> // 創建一個響應式對象 const state = reactive({ counter: 1 }); // 立即運行一個函數,當響應式對象的屬性發生改變時重新執行。 effect(() => { document.querySelector("#app").innerHTML = state.counter; }); // 2s 后視圖更新 setTimeout(() => { state.counter += 1; }, 2000); </script>
我們用 reactive 創建了一個響應式對象 state,并調用了 effect 方法,該方法接受一個副作用函數,effect 的執行會立即調用副作用函數,并將 state.counter 賦值給 #app.innerHTML;兩秒后,state.counter += 1,此時,effect 的副作用函數會重新執行,頁面也會變成 2.
內部的執行過程大概如下圖所示:
調用 reactive() 返回一個 Proxy 代理對象,并劫持對象的 get 與 set 操作
調用 effect() 方法時,會訪問屬性 state.counter,此時會觸發 proxy 的 get 操作。
get 方法會調用 track() 進行依賴收集;建立一個對象(state)、屬性(counter)、effect 副作用函數的依賴關系;
set 方法會調用 trigger() 進行依賴更新;通過對象(state)與屬性(coutner)找到對應的 effect 副作用函數,然后重新執行。
reactive 會返回如下一個 Proxy 對象
const reactive = (target) => { return new Proxy(target, { get(target, key, receiver) { const res = Reflect.get(target, key, receiver); track(target, key); // 收集依賴 if (isObject(res)) { // 如果當前獲取的屬性值是一個對象,則繼續將為此對象創建 Proxy 代理 return reactive(res); } return res; }, set(target, key, value, receiver) { Reflect.set(target, key, value, receiver); trigger(target, key); // 依賴更新 }, }); };
let activeEffect; function effect(fn) { const _effect = function reactiveEffect() { activeEffect = _effect; fn(); }; _effect(); }
首先定義全局的 activeEffect,它永遠指向當前正在執行的 effect 副作用函數。effect 為 fn 創建一個內部的副作用函數,然后立即執行,此時會觸發對象的 get 操作,調用 track() 方法。
effect(() => { // effect 的立即執行會訪問 state.counter,觸發了對象的 get 操作。 document.querySelector("#app").innerHTML = state.counter; });
track 會建立一個 對象(state) => 屬性(counter) => effect 的一個依賴關系
const targetMap = new WeakMap(); function track(target, key) { if (!activeEffect) { return; } let depsMap = targetMap.get(target); if (!depsMap) { targetMap.set(target, (depsMap = new Map())); } let dep = depsMap.get(key); if (!dep) { depsMap.set(key, (dep = new Set())); } if (!dep.has(activeEffect)) { dep.add(activeEffect); } }
執行完成成后我們得到一個如下的數據結構:
[ // map 集合 { key: {counter: 1} // state 對象, value: [ // map 集合 { key: "counter", value: [ // set function reactiveEffect() {} // effect 副作用函數 ], } ], }, ];
注意:當我們調用 effect 時,會將當前的副作用函數賦值給全局的 activeEffect,所以此時我們可以正確關聯其依賴。
當我們給 state.counter 賦值的時候就會觸發代理對象的 set 操作,從而調用 trigger 方法
setTimeout(() => { // 給 counter 屬性賦值會觸發 set 操作 state.counter += 1; }, 2000);
function trigger(target, key) { const depsMap = targetMap.get(target); if (!depsMap) return; const effects = depsMap.get(key); effects && effects.forEach((effect) => effect()); }
到此,關于“Vue3的響應式原理是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。