Vue3 學習筆記之 watchEffect

2021-10-11 22:19:50 字數 4578 閱讀 8346

最近在看 vue3 的一些新 feature,順道學習了一些 hooks 程式設計的思想,感覺挺有啟發的。今天就以 watcheffect 這個很小的 case 為例,開啟我的 vue3 學習筆記。

對所有初學者來說,vue2 到 vue3 最直觀的改變就是 composition api——幾乎所有的 vue2 options 方法都被放到了 setup 函式裡:

+ import  from 'vue'

export default );

+ onmounted(() => );

+ watcheffect(() => );

+ return ;

+ },

- data: () => (),

- mounted(),

- watch: ,

};複製**

這是乙個比較大的風格轉變,通俗來說,就是從基於物件的程式設計(oop)轉向了函式式程式設計(fp)。

初學者可能分辨不清 oop 和 fp 的區別。大家注意看onmountedwatcheffect方法的引數——箭頭函式,大致能體會到不同之處了。

oop 的特點是:物件(或 class)是資料(variable)和邏輯(methods)的封裝。在 vue2 時代,我們經常寫如下**:

// vue2

export ),

methods: $`,

},watch: ;

}}複製**

vue2 的內部實現比較複雜,不過對外表現的程式設計模式基本就是:物件呼叫自己的資料和方法——this+.操作。所以在 vue2 時代,我們通常會把相關的資料和操作寫在同乙個物件裡。但是到了 vue3 的setup裡,你幾乎不會用到this了;變成了讓函式來呼叫物件或是另乙個函式——就是 fp 的特點了。

// vue3

import from "vue";

export default $`;

watcheffect(() => );

return ;

},};複製**

本文不想過多介紹函式式程式設計,但是既然 vue3 的風格轉向了 fp,我們得遵守 fp 的規則——函式只應該做一件事,就是返回乙個值。下面的乙個 vue 元件就可以看做乙個函式,通過 props 傳入乙個引數 name,返回乙個 html。

複製**

上面這個函式有什麼特點呢?

相同的輸入產生相同的輸出

不能有語義上可觀察的函式***

這個就是經典的純函式(pure function)。

不過現實中乙個 vue 元件可能還要做其他很多事,如:

這些其他改變就是所謂的***(side effect)。在 fp 的世界裡,我們不能向 vue2 那樣簡單地呼叫全域性外掛程式了(this.$tthis.$routerthis.$store……);而是通過間接的手段——即通過其他函式呼叫——包含***。vue3 就提供了乙個通用的***鉤子(hook)叫做watcheffect(從名字上也可見一斑),就是我們今天的主角了。

兜兜轉轉,我們再來介紹一下watcheffect的用法,借助 typescript,我們可以很清晰地看到該函式的定義:

function watcheffect(

effect: (oninvalidate: invalidatecbregistrator) => void,

options?: watcheffectoptions

): stophandle;

inte***ce watcheffectoptions

inte***ce debuggerevent

type invalidatecbregistrator = (invalidate: () => void) => void;

type stophandle = () => void;

複製**

watcheffect自己是函式,它的第乙個引數——effect——也是函式(函式是一等公民,可以用在各個地方)。effect,顧名思義,就是包含***的函式。如下**中,***函式的作用是:當count被訪問時,旋即在控制台打出日誌。

// vue3

import from "vue";

export default ;

},};複製**

如上**會列印出010是出於 vue 響應式設計,在響應式元素(count)依賴收集階段會執行一次effect函式;0是來自settimeout裡對count修改的操作。

大家注意到沒有?watcheffect的第乙個引數——effect函式——自己也有引數:叫oninvalidate,也是乙個函式,用於清除effect產生的***。(而且oninvalidate的引數也是函式,哈哈!)

*p.s.fp 就是這樣,函式巢狀函式;初學者可能有點暈,習慣就好*

oninvalidate被呼叫的時機很微妙:它只作用於非同步函式,並且只有在如下兩種情況下才會被呼叫:

effect函式被重新呼叫時

當***被登出時(如元件被解除安裝了)

如下**中,oninvalidate會在id改變時或停止偵聽時,取消之前的非同步操作(asyncoperation):

import  from "./asyncoperation";

const id = ref(0);

watcheffect((oninvalidate) => );

});複製**

***是隨著元件載入而發生的,那麼元件解除安裝時,就需要清理這些***。watcheffect的返回值——stophandle依舊是乙個函式——就是用在這個時候。如下stophandle可以在setup函式裡顯式呼叫,也可以在元件被解除安裝時隱式呼叫。

setup() );

// 之後

stophandle();

}複製**

watcheffect還有第二個引數叫options,型別是watcheffectoptions,乙個很複雜的介面。雖然很少能被用到吧,但也在這裡快速提一下。

第二個引數的主要作用是指定排程器,即何時執行***函式。比如,你希望***函式在元件更新前發生,可以將flush設為'pre'(預設是'post')。還有watcheffectoptions也可以用於 debug:ontrackontrigger選項可用於除錯乙個偵聽器的行為(當然只開發階段有效)。

// fire before component updates

watcheffect(

() => ,

, }

);複製**

watcheffect會在 vue3 開發中大量使用,這裡說幾個注意點:

如果有多個負效應,不要粘合在一起,建議寫多個watcheffect

watcheffect(() => );

複製**

watcheffect(() => );

watcheffect(() => );

複製**

watcheffect也可以放在其他生命週期函式內

比如你的***函式在首次執行時就要呼叫 dom,你可以把他放在onmounted鉤子裡:

vue3學習筆記

vue3 1.context.emit update xx props.xx 可 v model xx更新xx的值 個人記憶,雙向繫結 需要雙向改變的值 代替 vue2 sync 2.元件上繫結的事件預設是繫結第一層,可使用inheritattrs false 取消預設,在需要繼承的屬性的標籤使用v...

vue3學習總結

v model 2.x語法 title.sync oldvalue childcomponent this emit update title newvalue 3.x語法v model title oldvalue childcomponent 所有v model不到引數,一定要改變道具和事件名稱...

Vue3學習記錄(二)

vue2中有data computed method等,我們有時候尋找乙個變數或者函式就需要翻閱整段 vue3提出了組合式api,並且提出了可以使用組合式api的地方 setup。p click add 加1button div template import from vue export def...