vue中通過watch監聽資料變化,帶來的效能優化
問題背景
為什麼要用 vuex?
在使用 Vue 進行元件化開發時,元件通訊是一個十分重要的部分。在 Vue 中,父子元件的關係可以總結為
- 父子元件通訊:父元件通過 props 向下傳遞資料給子元件
-
子父元件通訊:子元件通過 events 給父元件傳送訊息
- 使用 $on(eventName) 監聽事件
- 使用 $emit(eventName) 觸發事件
- 非父子元件通訊:使用一個空的 Vue 例項作為中央事件匯流排
父子,子父 元件之間的通訊是很輕鬆的,通過 props 和 events 即可實現;但是往往我們的應用可能不只有這麼簡單的層級關係,在多層跨級元件如果通過 props 去傳遞,那意味著一層一層的往子元件傳遞,最終你可能不知道當前元件的資料最終來自哪個父元件(當然你可以逆著方向一層一層往上找),通過 events 事件機制顯然也存在著類似的問題。如果你覺得這樣也可以接受,你可能不需要 Vuex;但如果你在想有沒有什麼好的模式優雅的去解決,你可以繼續閱讀下面的部分。
狀態管理
我們通過傳送 action,提交 mutation 的方式,而非直接改變 store.state.count,是因為我們想要更明確地追蹤到狀態的變化。這個簡單的約定能夠讓你的意圖更加明顯,這樣你在閱讀程式碼的時候能更容易地解讀應用內部的狀態改變。此外,這樣也讓我們有機會去實現一些能記錄每次狀態改變,儲存狀態快照的除錯工具。有了它,我們甚至可以實現如時間穿梭般的除錯體驗。由於 store 中的狀態是響應式的,在元件中呼叫 store 中的狀態簡單到僅需要在計算屬性中返回即可。觸發變化也僅僅是在元件的 methods 中提交 mutations。
- actions:操作行為處理模組。負責處理 Vue Components 接收到的所有互動行為。包含同步/非同步操作,向後臺 API 請求的操作就在這個模組中進行,包括觸發其他 action 以及提交 mutation 的操作。該模組提供了 Promise 的封裝,以支援 action 的鏈式觸發。
- mutations:狀態改變操作方法。是 Vuex 修改 state 的唯一推薦方法,其他修改方式在嚴格模式下將會報錯。該方法只能進行同步操作,且方法名只能全域性唯一。操作之中會有一些 hook 暴露出來,以進行 state 的監控等。
- state:頁面狀態管理容器物件。集中儲存 Vue components 中 data 物件的零散資料,全域性唯一,以進行統一的狀態管理。頁面顯示所需的資料從該物件中進行讀取,利用 Vue 的細粒度資料響應機制來進行高效的狀態更新。
- getters:state 物件讀取方法。Vue Components 通過該方法讀取全域性 state 物件。
資料流轉
用 getters 將 state 資料對映到當前元件,在 vue component 中傳送 action,在 action 中請求資料,並呼叫 mutations,mutationg 改變 state 的資料,從而實現資料更新導致的頁面更新。
問題描述
在正在做的專案中遇到這樣一個問題,當頁面進行分頁請求時,連續點選當前頁會一直髮送請求,極大的降低了效能,於是決定減少請求次數,只有 pageNum 發生變化時才去請求。
實現過程
vue 中有 watch 這個 api 它可以監聽物件及對應值的變化從而在資料發生變化時呼叫 action,於是寫了如下程式碼
實現分頁操作的繫結事件
@redirect="handlePageRedirect"
傳送 action 將點選的 pageNum 儲存在 state 裡 監聽 pageNum 的變化來發送 action 來請求資料,當然還需通過 computed 將 state 裡需要監聽的資料對映到當前元件
發現數據並沒有被監聽,並嘗試列印監聽的資料,程式碼如下
watch: {
'aList.pageNum'(newVal, oldVal) {
console.log(newVal,oldVal);
}
}
問題定位
開啟除錯工具,發現 state 資料中並沒有 pageNum 這個資料,但在檔案 state.js 中是有預設值的,查詢發現,在 mutations 中將原本 state 的預設值覆蓋 state.js 中監聽的資料 在 mutations 中將 state 資料覆蓋程式碼,程式碼如下
state.aList = {
list: data.list,
total: data.total,
pageSize: data.pageSize
}
查閱資料瞭解到 mutation 改變 state 資料只需要將新值加入到原來物件,而不是覆蓋它,程式碼如下
故修改程式碼為
state.aList = {
...state.aList,
...data
}
總結知識
watch 監聽的方式
- 物件中屬性的 watch
watch: {
'aList.pageNum'(newVal, oldVal) {
console.log(newVal,oldVal);
}
}
- 某個物件的 watch tips: 只要 bet 中的屬性發生變化(可被監測到的),便會執行 handler 函式;如果想監測具體的屬性變化,如 pokerHistory 變化時,才執行 handler 函式,則可以利用計算屬性 computed 做中間層。 如果想監測具體的屬性變化,如 pokerHistory 變化時,才執行 handler 函式,則可以利用計算屬性 computed 做中間層。 注意 deep: true 必須加。
- 監聽url的變化傳送請求(可獲取url上引數)
watch: {
$route({ query }) {
this.searchUser([
{},
{
appId: query.appId
}
]);
}
}
- mutations 中改變資料的方式,將新值與容器中的值合併,並不是直接覆蓋。
- watch 暫且寫到這裡,歡迎大家來補充留言。