開發中我們經常遇到這樣的問題:每次切換頁面,我需要在父組件重新請求一次要切換到的頁面的一些狀態和數據,然后把這些狀態和數據傳遞給子組件,然后對這些數據進行加工渲染到頁面上。
那么問題來了,我們的子組件如何確定自己能知道自己拿到的是最新的數據而不是上一次的數據呢?也就是說,在我子組件要對父組件傳來的數據進行加工時如何保證這是我最新一次拿到的當前頁面的數據?
舉個例子:
我們將圖片左端的滑塊放置到60px位置上,然后在handleMouseup事件中更新釋放滑塊的狀態並向父組件提交一次拖動的狀態信息(比如image_id,xx.xx.height=60px等等這樣的信息),在父組件中把這些狀態信息通過axios.put方法放置到后端來存儲,這樣的話再次加載該圖片進行請求時,就能請求到對應的滑塊位置(xx.xx.height=60px這個信息),並根據這個信息進行重制滑塊位置。這時當下次再次切換到當前圖片的頁面時,第一步我們需要在子組件的圖片加載監聽事件中添加一個設置滑塊狀態的監聽器,第二步要在監聽器中通過getBoundingClientRect()方法獲取到獲取該圖片元素相對於視窗的位置集合。集合中有top, right, bottom, left等屬性,把這些信息設置給子組件需要加工的信息中,第三步我們要重制滑塊位置,比如我們把重制滑塊位置的一系列方法放置在setting()函數中,並在監聽器中調用setting()。這時問題來了:如何保證我們在重制滑塊位置時拿到的是最新的數據值呢?要知道我們用的信息是父組件傳遞過來的,如果父組件請求xx.xx.height=60px等一系列信息時時間過長怎么辦,我們立即調用setting是不是就會導致滑塊高度缺失或者出現並不是height=60px的情況了?
解決方案1:定時器
setTimeout(() => { this.setting() }, 200)
優點:簡潔明了
缺點:要注意父組件的異步事件隊列和子組件的異步事件隊列是幾乎同時執行的,也就是說當axios的請求超過200毫秒還沒返回時,子組件那邊已經執行完setTimeout了,那進行設置滑塊所用到的狀態只能是老的狀態,這就出現了狀態缺失的問題。
解決方案2:監聽保證順序執行
在子組件中設置一個計數器,在父組件中監聽這個計數器,當子組件執行完第二步時將計數器自增,這樣父組件監聽到改變並在watch中執行axios方法請求資源數據,並在拿到數據后調用子組件的setting方法
優點:穩定,嚴格保證了順序執行
缺點:流程復雜,代碼繁瑣,不利於維護
解決方案3:promise
將請求axios的方法頭加上async,在axios前加await,並將該方法拿到的promise賦值給一個參數,再把這個參數傳遞給子組件,這樣我們只需在子組件中await這個參數(等promise拿到參數狀態置為fullfilled)再執行setting進行滑塊位置的設定即可
優點:穩定,代碼簡潔便於維護
缺點:要保證在頁面刷新時執行一次傳送從而使子組件重制promise狀態
綜上所述:最理想的解決方案是第三種,這充分利用到了async和await的簡化promise並保證拿到返回的結果再去執行下一步