在Vue中,數據響應式是一個核心概念,它使得當數據變化時,相關的視圖會自動更新。為了更靈活地處理數據的變化,Vue提供了多種方式,其中包括watch、computed和watchEffect。
watch是Vue中一個非常強大的特性,它允許你監聽數據的變化并做出相應的反應。它有兩種用法:一是監聽一個具體的數據變化,二是監聽多個數據的變化。
// 監聽單個數據watch('someData', (newVal, oldVal) => { // 做一些事情});// 監聽多個數據watch(['data1', 'data2'], ([newVal1, newVal2], [oldVal1, oldVal2]) => { // 做一些事情});
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用于計算派生數據。它依賴于其他響應式數據,并且只有在相關數據發生變化時才會重新計算。
computed(() => { return someData * 2;});
computed的實現原理相對于watch更為復雜,它依賴于getter和setter的機制。在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是Vue 3新增的特性,它用于監聽一個函數內部的響應式數據變化,當變化時,函數會被重新執行。
watchEffect(() => { // 依賴于響應式數據的操作});
watchEffect是Vue 3中引入的響應式API,它用于執行一個響應式函數,并在函數中響應式地追蹤其依賴。與watch不同,watchEffect不需要顯式地指定依賴,它會自動追蹤函數內部的響應式數據,并在這些數據變化時觸發函數重新執行。
以下是watchEffect的簡單用法:
import { watchEffect, reactive } from 'vue';const state = reactive({ count: 0,});watchEffect(() => { console.log(state.count);});
在這個例子中,watchEffect內部的函數會自動追蹤state.count的變化,并在其變化時觸發函數執行。
現在,讓我們來探討watchEffect的實現原理。
首先,watchEffect的核心是依賴追蹤和觸發。Vue 3中的響應式系統使用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返回一個停止函數,用于停止對響應式數據的追蹤。
watch主要用于監聽特定的數據變化并執行回調函數。它可以監聽數據的變化,并在滿足一定條件時執行相應的操作。常見的使用場景包括:
watch(() => state.data, async (newData, oldData) => { // 異步操作 await fetchData(newData);});
watch(() => state.user.address.city, (newCity, oldCity) => { console.log(`City changed from ${oldCity} to ${newCity}`);});
computed用于創建一個計算屬性,它依賴于其他響應式數據,并且只有在依賴數據發生變化時才重新計算。常見的使用場景包括:
const fullName = computed(() => `${state.firstName} ${state.lastName}`);
const result = computed(() => { // 避免重復計算 if (someCondition) { return heavyCalculation(); } else { return defaultResult; }});
watchEffect用于執行一個響應式函數,并在函數內部自動追蹤依賴。它適用于不需要顯式指定依賴,而是在函數內部自動追蹤所有響應式數據變化的場景。常見的使用場景包括:
watchEffect(() => { console.log(`Count changed to ${state.count}`);});
watchEffect(() => { // 處理動態變化的數據 handleDynamicData();});
總體而言,watch適用于需要有條件地監聽數據變化的場景,computed適用于創建派生數據和性能優化,而watchEffect適用于自動追蹤依賴的場景。在實際應用中,根據具體需求選擇合適的API可以更好地發揮Vue的響應式能力。
本文鏈接:http://www.www897cc.com/showinfo-26-35340-0.html再也不怕面試官問watch、computed、watchEffect的區別了
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 八股文-如何理解Java中的多態