日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

vue3解读—reactivity响应式实现

發布時間:2023/12/8 vue 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 vue3解读—reactivity响应式实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言:Vue3 中引入了proxy進行數據劫持,而effect是響應式系統的核心,而響應式系統又是 vue3 中的核心,所以vue3的解讀要從 effect 開始講起。

1.reactivity和effect的使用

目前vue3的各個模塊都可以單獨安裝,首先我們需要安裝npm i @vue/reactivity,從中引入我們需要的方法,下面是我簡單寫一段測試代碼。

const { reactive, effect } = require("@vue/reactivity"); let a = reactive({value: 1, }); let b; effect(() => {b = a.value + 10;console.log(b); }); a.value = 10;

先別急著看我的輸出,想想自己心中的答案是什么?

下面公布控制臺的實際輸出:

總結:我們會發現effect函數執行了兩次,一次是我們往effect函數傳入匿名函數時,它立即執行了一次;接下來是我們對響應式變量a.value進行重新賦值時(或者說effect內函數所依賴的響應式變量發生變化時)它又執行了一次。

接下來我們就好好思考下,如何設計一個reactive方法,將傳入的值變成響應式,以及實現一個effect函數,其內函數所依賴的響應式數據變化時,該函數會再次執行。

2.Dep和effect的實現

reactive會將傳入的變量變成響應式數據,包括對象等數據;地基需要從下往上一層一層的搭建,我們這里先實現將單一變量編譯成響應式數據,并用effct對其監聽。廢話不多說,上代碼:

第一步:

class Dep {constructor(val) {this._val = val;}get value() {return this._val;}set value(newVal) {this._val = newVal} } const dep = new Dep(10); console.log('取值:', dep.value); dep.value = 20; console.log('賦值:', dep.value);

我們通過class類去創建一個簡單的變量,用其構造器constructor初始化對象屬性,使用setter和getter存取器攔截該屬性的存取行為。此時dep就是響應式數據嗎?想啥呢!但我們會很熟悉后面的取存值行為,這不就是我們在vue3中使用ref聲明變量時,取值和賦值的寫法嗎!

有了這一步的鋪墊,我們接下來的思路是不是更清晰了,只需要在初始化一個Dep時,收集依賴該dep的函數,并在dep值發生變化時,再次執行這個依賴函數,是不是就能實現前面reactive和effect所達到的效果。ready go

第二步:

let currentEffect; class Dep {constructor(val) {this.effects = new Set(); // 儲存依賴當前變量的函數,并去重this._val = val;}get value() {this.depend();return this._val;}set value(newVal) {this._val = newValthis.notice(); // 賦值時觸發依賴}// 收集依賴depend() {if(currentEffect) { // 要記得判空this.effects.add(currentEffect);}}// 觸發依賴notice() {this.effects.forEach(effect => {effect();});} } const effectWatch = (effect) => {currentEffect = effect;effect(); // 別忘了首先就會執行一次currentEffect = null; }const dep = new Dep(10); let b; effectWatch(() => {b = dep.value + 10;console.log('effectWatch', b); }); dep.value = 20;

為了講解時方便區分,所以我在實現effect時,重新取名叫effectWatch;不墨跡了,趕緊看代碼,相對于第一步,Dep類新增了兩個方法,分別是儲存依賴的函數和觸發依賴的函數。首先effectWatch在調用時就會執行一次依賴函數,并且是在effectWatch的參數中取dep.value值時,就會將當前依賴函數儲存,當我們對dep.value賦值時,會再次觸發依賴的函數。

到此為止我們只是實現了一個簡化單一的‘reactive’和effect,真正的reacive可不僅僅只是傳一個普通字符的功能,一起想想下一步該怎么做呢?

3.reactive實現

前面我們已經實現了簡單地Dep,它只是一個單一的變量,遠遠不能滿足我們的開發需求。如果我們通過嵌套調用Dep,是不是就能實現reactive的功能了?而且開局我們已經了解到需要使用到proxy對數據進行劫持,那么是不是就好實現多了。

第一步

const reactive = (raw) => {return new Proxy(raw, {get(target, key) {console.log('get----', target[key]);return Reflect.get(target, key);},set(target, key, value) {console.log('set----', key, value);return Reflect.set(target, key, value);}}); } const user = reactive({name: '春賞百花冬觀雪', }); user.name; user.age = 24; user.age;

我們先科普下proxy,就作者而言,很早就學習過該方法,但對于它的應用確實少的可憐(唯唯諾諾的小菜雞)。proxy就是在我們訪問對象前添加了一層攔截,從而實現基本操作的攔截和自定義(我理解為過濾),而且proxy常常與Reflect成對出現,Reflect也就是反射,它的出現簡化了我們調用_Object對象_的代碼,保持JS的簡單,它們之間的基情還需要讀者自行去了解哦。

對于user我們可以理解為一個較為復雜的對象,此時的它的每一個屬性key所對應的值是不是相當于我前面的dep呢,那么我們只需要再訪問該key值時將它通過Dep初始化,從而使整個user的任意屬性值發生變化,那么所依賴的函數也能再次執行了,整個user也就成了響應式對象了。從代碼來看,第一步依舊是 利用存取器對該user對象進行監聽。

第二步

const targetMap = new Map(); // 用于搜集經過reactive初始化的變量 const getDep = (target, key) => {let depsMap = targetMap.get(target); // 從targetMap取,如果有的話if (!depsMap) { // 沒有就先儲存depsMap = new Map();targetMap.set(target, depsMap);}let dep = depsMap.get(key); // 并將dep與target的key建立連接if (!dep) {dep = new Dep();depsMap.set(key, dep);}return dep; }; const reactive = (raw) => {return new Proxy(raw, {get(target, key) {const dep = getDep(target, key);dep.depend(); // 當我們訪問對象每個屬性時,都會收集依賴return Reflect.get(target, key);},set(target, key, value) {const dep = getDep(target, key);const result = Reflect.set(target, key, value); // 重新設置值之后dep.notice(); // 觸發依賴return result; // 再return}}); }; const user = reactive({name: '春賞百花冬觀雪', }); effectWatch(() => {user.name;console.log('effect---', user.name); }); user.name = '曉看天色暮觀云';

這里要注意為什么接收Reflect.set后再return拋出,因為我們需要將user.name的值更新后,緊接著觸發我們收集到的依賴,最后才能拋出以完成set。

作者也是前端小白一枚,只是通過自己的學習并記錄以方便自己的回顧,也希望讀者大佬們能提出寶貴意見,共同進步。

總結

以上是生活随笔為你收集整理的vue3解读—reactivity响应式实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。