[vue2/vue3] 詳細剖析watch、computed、watchEffect的區別,原理解讀

前言:哈嘍,大家好,我是前端菜鳥的自我修養!今天給大家分享【深入剖析watch、computed、watchEffect的區別】,并提供具體代碼幫助大家深入理解,徹底掌握!原創不易,如果能幫助到帶大家,歡迎?收藏+關注?哦 💕

?

🌈🌈文章目錄

一、watch

1.使用語法

2.watch的實現原理?

二、computed

1.簡單使用

2.computed的實現原理

三、watchEffect

1.簡單使用

2.小結

3.watchEffect的實現原理

4.注意事項

1. 避免過度監聽

2. 異步操作需謹慎處理

3. 避免無限循環

四、實際開發當中該怎么去選擇

?1.watch

1.1 異步操作觸發

1.2 深度監聽

2.computed

2.1?派生數據?

2.2?性能優化

3.watchEffect

3.1?自動依賴追蹤

3.2?動態數據處理

五、總結

?

在Vue中,數據響應式是一個核心概念,它使得當數據變化時,相關的視圖會自動更新。為了更靈活地處理數據的變化,Vue提供了多種方式,其中包括watch、computed和watchEffect

一句話概括watch ?適用于需要有條件地監聽數據變化的場景,computed??適用于創建派生數據和性能優化,而watchEffect?適用于自動追蹤依賴的場景。在實際應用中,根據具體需求選擇合適的API可以更好地發揮Vue的響應式能力。

一、watch

1.使用語法

watch是Vue中一個非常強大的特性,它允許你監聽數據的變化并做出相應的反應。它有兩種用法:一是監聽一個具體的數據變化,二是監聽多個數據的變化。

// 監聽單個數據
watch('someData', (newVal, oldVal) => {// 做一些事情
});// 監聽多個數據
watch(['data1', 'data2'], ([newVal1, newVal2], [oldVal1, oldVal2]) => {// 做一些事情
});

2.watch的實現原理?

Vue中watch的實現主要依賴于Watcher這個核心類。當調用watch時,實際上是創建了一個Watcher實例,并將回調函數和需要監聽的數據傳遞給這個實例。

// 簡化版的watch實現
function watch(source, cb) {const watcher = new Watcher(source, cb);
}

Watcher類的構造函數接收兩個參數,分別是需要監聽的數據(可以是一個字符串,也可以是一個返回值的函數)回調函數。在構造函數中,會對數據進行求值,然后將這個Watcher實例添加到數據的依賴列表中。

class Watcher {constructor(source, cb) {this.getter = typeof source === 'function' ? source : () => this.vm[source];this.cb = cb;this.value = this.get();}get() {pushTarget(this); // 將當前Watcher實例壓棧const value = this.getter.call(this.vm); // 觸發數據的getter,將當前Watcher實例添加到依賴列表中popTarget(); // 將當前Watcher實例出棧return value;}update() {const oldValue = this.value;this.value = this.get();this.cb(this.value, oldValue);}
}

?簡單來說,watch的實現原理就是通過Watcher實例來監聽數據的變化,當數據變化時,觸發update方法執行回調函數

二、computed

1.簡單使用

computed用于計算派生數據。它依賴于其他響應式數據,并且只有在相關數據發生變化時才會重新計算

computed(() => {return someData * 2;
});

2.computed的實現原理

computed的實現原理相對于watch更為復雜,它依賴于gettersetter的機制。在Vue中,computed的定義是一個包含get和set方法的對象

const computed = {get() {return someData * 2;},set(value) {someData = value / 2;}
};

在computed的實現中,當訪問計算屬性時,實際上是執行了get方法,而在數據變化時,會執行set方法。這里主要使用了Object.defineProperty這個JavaScript的特性。

function createComputedGetter() {return function computedGetter() {const value = getter.call(this); // 執行計算屬性的get方法track(target, TrackOpTypes.GET, 'value'); // 添加依賴return value;};
}function createComputedSetter() {return function computedSetter(newValue) {setter.call(this, newValue); // 執行計算屬性的set方法trigger(target, TriggerOpTypes.SET, 'value'); // 觸發更新};
}function computed(getterOrOptions) {const getter = typeof getterOrOptions === 'function'? getterOrOptions: getterOrOptions.get;const setter = getterOrOptions.set;const cRef = new ComputedRefImpl(getter,setter,isFunction(getterOrOptions) || !getterOrOptions.get);return cRef;
}class ComputedRefImpl {// 構造函數constructor(getter, setter, isReadonly) {// ...this.effect = effect(getter, {lazy: true,scheduler: () => {if (!this._dirty) {this._dirty = true;triggerRef(this);}},});}// ...
}

在上述代碼中,createComputedGetter和createComputedSetter用于創建計算屬性的getter和setter。computed函數接收一個getter函數,并通過Object.defineProperty將getter和setter添加到計算屬性的引用對象中。

當計算屬性被訪問時,會觸發getter,此時會將當前計算屬性添加到依賴列表中。當計算屬性的依賴數據發生變化時,會觸發setter,并通過triggerRef觸發計算屬性的更新。

三、watchEffect

1.簡單使用

watchEffect()函數用于創建一個自動追蹤依賴的響應式副作用。它會在初始化時會立即執行一次,并自動追蹤在回調函數中使用的所有響應式數據,在這些數據發生變化時重新運行回調函數。

例如,在每當 todoId 的引用發生變化時使用偵聽器來加載一個遠程資源,如果用watch,是這么寫:

<template><div>Test</div>
</template><script setup>import { ref, watch } from 'vue'const todoId = ref(1)const data = ref(null)watch(todoId,async () => {const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)data.value = await response.json()console.log(data.value)},{ immediate: true })
</script>

打印:

?

但是用了watchEffect()就可以簡化為:

<template><div>Test</div>
</template><script setup>import { ref, watchEffect } from 'vue'const todoId = ref(1)const data = ref(null)watchEffect(async () => {const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)data.value = await response.json()console.log(data.value)})
</script>

打印:

?

2.小結

兩者都立即打印了data。但下面的例子中,回調會立即執行,不需要指定 immediate: true。在執行期間,它會自動追蹤 todoId.value 作為依賴(和計算屬性類似)。每當 todoId.value 變化時,回調會再次執行。有了 watchEffect(),我們不再需要明確傳遞 todoId 作為源值。

從這個角度來看,watchEffect()的作用類似于Vue2中的computed,即依賴項發生變化,自己也跟著改變。但與computed不同,watchEffect()沒有返回值,而是直接執行回調函數

3.watchEffect的實現原理

watchEffect是Vue3中引入的響應式API,它用于執行一個響應式函數,并在函數中響應式地追蹤其依賴。與watch不同,watchEffect不需要顯式地指定依賴,它會自動追蹤函數內部的響應式數據,并在這些數據變化時觸發函數重新執行

首先,watchEffect的核心是依賴追蹤和觸發。Vue3中的響應式系統使用ReactiveEffect類來表示一個響應式的函數。

class ReactiveEffect {constructor(fn, scheduler = null) {// ...this.deps = [];this.scheduler = scheduler;}run() {// 執行響應式函數this.active && this.getter();}stop() {// 停止追蹤cleanupEffect(this);}
}export function watchEffect(effect, options = {}) {// 創建ReactiveEffect實例const runner = effect;const job = () => {if (!runner.active) {return;}if (cleanup) {cleanup();}// 執行響應式函數return runner.run();};// 執行響應式函數job();// 返回停止函數return () => {stop(runner);};
}

在上述代碼中,ReactiveEffect類表示一個響應式的函數。watchEffect函數接收一個響應式函數,并創建一個ReactiveEffect實例。在執行時,該實例會追蹤函數內部的響應式數據,并在這些數據變化時觸發函數重新執行。

watchEffect返回一個停止函數,用于停止對響應式數據的追蹤

4.注意事項

1. 避免過度監聽

由于watchEffect()會追蹤使用到的所有響應式數據,因此要確保在回調函數中只使用必要的響應式數據,避免造成不必要的渲染開銷。

2. 異步操作需謹慎處理

由于watchEffect()會立即執行回調函數,如果在回調函數中進行異步操作,需要謹慎處理,以免導致意外行為或副作用。

<script setup>
import { watchEffect } from 'vue'// 它會自動停止
watchEffect(() => {})// ...這個則不會!
setTimeout(() => {watchEffect(() => {})
}, 100)
</script>
3. 避免無限循環

當在watchEffect()的回調中修改響應式數據時,可能會導致無限循環。要避免此問題,可以使用watch()函數并設置?immediate: true選項,或者使用ref來存儲臨時數據。

四、實際開發當中該怎么去選擇

?1.watch

watch主要用于監聽特定的數據變化并執行回調函數。它可以監聽數據的變化,并在滿足一定條件時執行相應的操作。常見的使用場景包括:

1.1 異步操作觸發

當某個數據發生變化后,需要進行異步操作,比如發起一個網絡請求或執行一段耗時的操作。

watch(() => state.data, async (newData, oldData) => {// 異步操作await fetchData(newData);
});

1.2 深度監聽

監聽對象或數組的變化,并在深層次的數據變化時執行回調

watch(() => state.user.address.city, (newCity, oldCity) => {console.log(`City changed from ${oldCity} to ${newCity}`);
});

2.computed

computed用于創建一個計算屬性,它依賴于其他響應式數據,并且只有在依賴數據發生變化時才重新計算。常見的使用場景包括:

2.1?派生數據?

根據現有的數據計算出一些派生的數據,而不必每次都重新計算

const fullName = computed(() => `${state.firstName} ${state.lastName}`);

2.2?性能優化

避免不必要的重復計算,提高性能。

const result = computed(() => {// 避免重復計算if (someCondition) {return heavyCalculation();} else {return defaultResult;}
});

3.watchEffect

watchEffect用于執行一個響應式函數,并在函數內部自動追蹤依賴。它適用于不需要顯式指定依賴,而是在函數內部自動追蹤所有響應式數據變化的場景。常見的使用場景包括:

3.1?自動依賴追蹤

函數內部的所有響應式數據都被自動追蹤,無需顯式指定

watchEffect(() => {console.log(`Count changed to ${state.count}`);
});

3.2?動態數據處理

處理動態變化的數據,無需手動管理依賴

watchEffect(() => {// 處理動態變化的數據handleDynamicData();
})

五、總結

watch ?適用于需要有條件地監聽數據變化的場景,computed??適用于創建派生數據和性能優化,而watchEffect?適用于自動追蹤依賴的場景。在實際應用中,根據具體需求選擇合適的API可以更好地發揮Vue的響應式能力。

??好了,本文就到這里吧,點個關注再走嘛~?

🚀?個人簡介:7年開發經驗,某大型國企前端負責人,信息系統項目管理師、CSDN優質創作者、阿里云專家博主,分享前端相關技術與工作常見問題~
💟 作 ? ?者:前端菜鳥的自我修養??
📝 專 ? ?欄:vue從基礎到起飛
🌈 若有幫助,還請?關注?點贊?收藏??,不行的話我再努努力💪💪💪??

??更多專欄訂閱推薦:

👍?前端工程搭建
💕?前端常見問題匯總,避坑大全

📝?javascript深入研究

???GIS地圖與大數據可視化

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/37675.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/37675.shtml
英文地址,請注明出處:http://en.pswp.cn/web/37675.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

為什么企業應用開發,c++干不過java?

在開始前剛好我有一些資料&#xff0c;是我根據網友給的問題精心整理了一份「c的資料從專業入門到高級教程」&#xff0c; 點個關注在評論區回復“888”之后私信回復“888”&#xff0c;全部無償共享給大家&#xff01;&#xff01;&#xff01; C/C這種東西&#xff0c;根本…

使用Optimum的BetterTransformer為常見的transformer結構模型進行推理加速

概述 &#x1f917; Optimum 提供了一個名為 BetterTransformer 的 API&#xff0c;這是標準 PyTorch Transformer API 的快速路徑&#xff0c;能夠通過稀疏性和融合內核&#xff08;如 Flash Attention&#xff09;在 CPU 和 GPU 上實現有趣的加速。目前&#xff0c;BetterTr…

一個 API 客戶端和一份 TS 學習手冊

第75期&#xff1a; Insomnia&#xff1a;超好看的 API 客戶端 項目介紹&#xff1a; 一款適用于 GraphQL、REST、WebSockets 和 gRPC 的開源 API 客戶端&#xff0c;顏值超高。 跨平臺&#xff0c;支持 Mac、Windows 和 Linux。但不支持網頁版&#xff0c;需要下載客戶端。…

Supabase 自托管部署實踐

Supabase 是 Firebase 的開源替代品。使用 Postgres 數據庫、身份驗證、即時 API、邊緣函數、實時訂閱、存儲和向量嵌入來啟動您的項目。 Supabase介紹 Supabase 是一個開源的后端即服務&#xff08;BaaS&#xff09;平臺&#xff0c;提供了一系列工具和服務&#xff0c;幫助…

CrimsonEDR:一款惡意軟件模式識別與EDR策略評估工具

關于CrimsonEDR CrimsonEDR是一個功能強大的開源項目&#xff0c;該項目旨在幫助廣大研究人員識別特定的惡意軟件模式&#xff0c;以此來優化終端檢測與響應&#xff08;EDR&#xff09;的策略方案。通過使用各種不同的檢測方案&#xff0c;可以加深開發人員與研究人員加深對安…

SpringBoot入門實戰:SpringBoot整合WebSocket

1.背景介紹 SpringBoot是一個快速開發的框架&#xff0c;它可以幫助我們快速開發Web應用程序。SpringBoot整合WebSocket是SpringBoot的一個組件&#xff0c;它可以幫助我們快速開發WebSocket應用程序。 WebSocket是一種新的協議&#xff0c;它可以讓客戶端和服務器之間建立持久…

MSYS2教程(windows環境下使用linux工具)

MSYS2教程(windows環境下使用linux工具) 1.msys2簡介 MSYS2&#xff08;Minimal SYStem 2&#xff09;是一個集成了大量的GNU工具鏈、工具和庫的開源軟件包集合。它提供了一個類似于Linux的shell環境&#xff0c;可以在Windows系統中編譯和運行許多Linux應用程序和工具。 MS…

數據增強:目標檢測算法的煉金術

數據增強&#xff1a;目標檢測算法的煉金術 在目標檢測領域&#xff0c;數據增強技術是一種提高模型泛化能力和性能的關鍵方法。通過數據增強&#xff0c;我們可以從現有的訓練集中生成更多的訓練樣本&#xff0c;這些樣本通過應用不同的變換來模擬真實世界中的多樣性。本文將…

【網絡安全】一文帶你了解什么是【CSRF攻擊】

CSRF&#xff08;Cross-Site Request Forgery&#xff0c;跨站請求偽造&#xff09;是一種網絡攻擊方式&#xff0c;它利用已認證用戶在受信任網站上的身份&#xff0c;誘使用戶在不知情的情況下執行惡意操作。具體來說&#xff0c;攻擊者通過各種方式&#xff08;如發送惡意鏈…

excel修改批量一列單價的金額并保留1位小數

1.打開表格&#xff0c;要把單價金額變成現在的兩倍&#xff0c;數據如下&#xff1a; 2.把單價這一列粘貼到一個新的sheet頁面&#xff0c;在B2單元格輸入公式&#xff1a;A2*2 然后按enter回車鍵,這時候吧鼠標放到B2單元格右下角&#xff0c;會出現一個黑色的小加號&#xf…

《信創數據庫沙龍上海站:共話發展,智啟未來》

2024 年 6 月 29 日周六 14:00&#xff0c;信創數據庫沙龍在上海市徐匯區建國西路 285 號科投大廈 13 樓金星廳成功舉辦。本次活動吸引了眾多學術界和產業界的專家、學者以及技術愛好者參與。 活動中&#xff0c;多位嘉賓帶來了精彩分享。薛曉剛探討了 Oracle 在國內的前景&a…

EAGLE-2:一種高效無損的推測性采樣方法,提升LLM的推理速度。

歡迎關注我的公眾號&#xff1a;Halo咯咯 01。概述 北京大學的研究人員聯合微軟研究院、滑鐵盧大學以及Vector研究所共同推出了EAGLE-2&#xff0c;這是一種利用上下文感知的動態草圖樹來增強推測性采樣的方法。EAGLE-2在先前的EAGLE方法基礎上進行了改進&#xff0c;不僅顯著…

python列表、元組、集合、字典整理

特征對比 下面是Python中列表、元組、集合和字典的特征對比表格&#xff1a; 特征列表 (List)元組 (Tuple)集合 (Set)字典 (Dictionary)定義符號[ ]( ){ }{ }可變性可變不可變可變可變有序性有序有序無序無序元素訪問通過索引訪問&#xff0c;索引從0開始通過索引訪問&#x…

一個啟動腳本例子

一、全部代碼 #!/bin/bash DATE$(date %Y%m%d)SOURCE"abc.jar" TARGET"backup/abc.jar.jew.$DATE"if [ -f "$SOURCE" ]; thencp "$SOURCE" "$TARGET" firm -f abc.jar mv abc_1.jar abc.jarpidNumps -ef | grep $SOURCE |…

【源碼+文檔+調試講解】基于vue的線上點餐系統

摘要 隨著信息技術在管理上越來越深入而廣泛的應用&#xff0c;管理信息系統的實施在技術上已逐步成熟。本文介紹了線上點餐系統的開發全過程。通過分析線上點餐系統管理的不足&#xff0c;創建了一個計算機管理線上點餐系統的方案。文章介紹了線上點餐系統的系統分析部分&…

電腦提示vcomp140.dll缺失怎么解決?vcomp140.dll是什么文件?

當你的電腦提示vcomp140.dll缺失的時候&#xff0c;你就應該要注意了&#xff0c;因為這個提示的出現&#xff0c;代表你的某個程序開不了&#xff01;想要程序能正常運行&#xff0c;那么只要修復好這個vcomp140.dll文件就可以了&#xff0c;下面我們就來給大家詳細的說說說vc…

超詳細之IDEA上傳項目到Gitee完整步驟

1. 注冊gitee 賬號密碼&#xff0c;gitee官網地址&#xff1a;Gitee官網&#xff0c;注冊完成后&#xff0c;登錄。 2. 創建倉庫&#xff0c;在主頁左下角有新建按鈕&#xff0c;點擊新建后會進入到此頁面填寫倉庫信息。 3. 創建完成后復制倉庫地址 4. 打開IntelliJ IDEA新建或…

python自動化之schedule

目錄 代碼&#xff08;以每5秒1次為例&#xff09;: 每5分鐘1次 每2小時1次 每天18:00執行 用到的庫&#xff1a;schedule&#xff0c;time 實現的效果&#xff1a;按秒來運行任務&#xff0c;按分鐘來運行任務&#xff0c;按小時來運行任務&#xff0c;按天來運行任務 代…

鴻蒙3.0WebView網絡錯誤問題

背景&#xff0c;榮耀9x&#xff0c;混淆才會出這個問題。 [ERROR:ssl_client_socket_impl.cc(981)] handshake failed; returned -1, SSL error code 1, net_error -2 NetError.java int SSLClientSocketImpl::DoHandshake() {crypto::OpenSSLErrStackTracer err_tracer(FRO…

Oracle新特性速遞:未來數據庫技術的無限可能

文章目錄 一、自治數據庫&#xff1a;智能化與自動化的革命二、機器學習集成&#xff1a;智能數據分析的新境界三、區塊鏈技術&#xff1a;確保數據完整性與透明性四、云原生數據庫&#xff1a;靈活擴展與快速部署五、人工智能優化器&#xff1a;智能查詢執行計劃《Oracle從入門…