1. 程式人生 > >vue中通過watch監聽資料變化,帶來的效能優化

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 裡 image監聽 pageNum 的變化來發送 action 來請求資料,當然還需通過 computed 將 state 裡需要監聽的資料對映到當前元件 image

發現數據並沒有被監聽,並嘗試列印監聽的資料,程式碼如下

watch: {
    'aList.pageNum'(newVal, oldVal) {
        console.log(newVal,oldVal);
    }
}

問題定位

開啟除錯工具,發現 state 資料中並沒有 pageNum 這個資料,但在檔案 state.js 中是有預設值的,查詢發現,在 mutations 中將原本 state 的預設值覆蓋 state.js 中監聽的資料 image在 mutations 中將 state 資料覆蓋程式碼,程式碼如下

state.aList = {
    list: data.list,
    total: data.total,
    pageSize: data.pageSize
}

查閱資料瞭解到 mutation 改變 state 資料只需要將新值加入到原來物件,而不是覆蓋它,程式碼如下 image
故修改程式碼為

state.aList = {
    ...state.aList,
    ...data
}

總結知識

watch 監聽的方式

  • 物件中屬性的 watch
watch: {
    'aList.pageNum'(newVal, oldVal) {
        console.log(newVal,oldVal);
    }
}
  • 某個物件的 watch imagetips: 只要 bet 中的屬性發生變化(可被監測到的),便會執行 handler 函式;如果想監測具體的屬性變化,如 pokerHistory 變化時,才執行 handler 函式,則可以利用計算屬性 computed 做中間層。 如果想監測具體的屬性變化,如 pokerHistory 變化時,才執行 handler 函式,則可以利用計算屬性 computed 做中間層。 注意 deep: true 必須加。
  • 監聽url的變化傳送請求(可獲取url上引數)
watch: {
        $route({ query }) {
            this.searchUser([
                {},
                {
                    appId: query.appId
                }
            ]);
        }
    }
  • mutations 中改變資料的方式,將新值與容器中的值合併,並不是直接覆蓋。
  • watch 暫且寫到這裡,歡迎大家來補充留言。