首發於:http://www.blazor.group:8000/topic/reply?tpid=9
開門見山,不介紹,不廢話
建議食用本文前先食用 https://www.cnblogs.com/wzxinchen/p/12082136.html
正常情況下,Blazor 的界面是怎樣刷新的?
Blazor 綁定(綁定就是刷新)機制有以下幾種
- 首次加載時的自動綁定
- 調用
StateHasChanged
強制重新綁定(重新綁定即刷新) - 注冊事件自動刷新
對於第三點,注冊事件是指類似於以下代碼
<BMenu OnClick="ShowMenu"></BMenu>
注意這代碼是瞎寫的,僅僅為了示例
在上面代碼中,注冊了 OnClick 事件,處理程序為 ShowMenu
OnClick 既然是事件,那它總得有個方法簽名,來規定 ShowMenu 的方法簽名是什么
一般來說,有兩種方法簽名:
- 直接就是一個委托
- 是
EventCallBack
結構體
對於第一種情況,OnClick 事件的定義往往是
[Parameter]
public Action OnClick {get;set;}
對於第二種情況,OnClick 事件的定義往往是
[Parameter]
public EventCallBack OnClick {get;set;}
這兩種情況在調用方注冊的方法是一樣的,那么這兩種情況有什么不一樣的?
不同點很小,第一種情況沒有什么好說的,第二種情況,EventCallBack
內部調用了 StateHasChanged
。也就是說,如果事件定義是第二種,那么在方法執行完后會自動刷新一次,如果是第一種,則需要手動刷新
默認情況下,Blazor 的刷新機制有怎樣的問題?
- 通過第一段我們知道,如果我們注冊了一個事件,而且這個事件是 EventCallBack,那么在方法調用完成之后會自動刷新
如果我們注冊的不是 OnClick 事件,而是 OnMouseMove 事件呢?那么 StateHasChanged 事件會被不停得調用,會給服務端造成極大壓力 - 我們在編寫頁面的時候,往往會在不同的地點手動調用 StateHasChanged 方法來刷新界面,假設 A 方法調用了 B 方法,B 又調用 C,並且 A 是類型為 EventCallBack 事件處理程序,然后 B、C里面最開始都調用了 StateHasChanged,這會刷新多少次?你的服務器資源會被吃光。
Blazor 如何解決這個問題?
Blazor 的 ComponentBase 類中,提供了 ShouldRender 這個方法,當這個方法返回為 false 時,不會執行渲染,即使你調用了 StateHasChanged,仍然不會渲染,這相當於讓你來決定,什么時候才是真的需要渲染,什么時候調用 StateHasChanged 才會生效。
你的 Blazui 組件界面為什么沒刷新?
基於 Blazor 的解決辦法,當組件第一次渲染完成之后,ShouldRender 會返回為 false,然后后面調用都返回 false,對於任意一個組件,若出現沒刷新的情況下,請考慮這個因素。
那么,如何讓 Blazui 組件進行刷新呢?方法很簡單,調用該組件的 MarkAsRequireRender 方法,標記該組件需要刷新。注意這個方法只是標記為需要刷新,如果不是自動調用的 StateHasChanged 方法,那么你需要手動調一次才刷新,這個方法 Blazui 封裝為 Refresh 方法,內部直接調的 StateHasChanged 方法
我調用了 MarkAsRequireRender 方法,為什么仍然沒刷新?
到了這步,仍然沒解決,可能會有些頭疼
因為要刷新的組件的父組件沒刷新
這里涉及到一個很重要的概念,Blazor 中,一個頁面中的所有組件,是一顆樹
可以簡單理解為二叉樹或是N叉樹,每一個節點,就是一個組件,這個節點下的直屬節點,是這個組件的子組件
<A>
<B>
<C>
</C>
</B>
</A>
A 是 B 的父組件,B 是 C 的父組件,要刷 C,你必須刷 B,注意這里的刷 B 並不會刷新 B 本身,而是刷的 B 的直屬子組件,現在,你應該可以理解,我要刷新 B,我又該刷誰?當然是刷 B 的父組件
為什么會這樣?因為你如果刷新 B,那么 B 所需要的參數根本不會更新,這樣一來也根本無法刷新數據,它的主要目的,是更新 B 的直屬子組件的所有參數,這樣才能刷新 B 的直屬子組件
因為當前頁面所屬組件沒刷新
Blazor 中,一切皆組件,當前頁面它仍然是個組件,按照第一點講到的,你大概可以理解這種情況該怎么辦,很簡單,設置當前頁面為需要刷新即可
若當前頁面沒有繼承 BComponentBase 這個類,則不需要考慮這個情況。
你的異步調用先后順序錯誤
這種情況是比較坑的,不容易發現。
考慮下面的代碼
public void Test(){
Task.Factory.StartNew(()=>{
//從數據庫拉數據
});
}
Test 是 OnClick 事件的處理方法,很簡單的一個情況,假設它不存在我們之前說的所有情況,這樣寫,仍然有概率不刷新,注意,是有概率,只是這概率特高。
當這個方法執行完並且開始執行 StateHasChanged 時,異步任務里面的拉取數據的代碼執行完了嗎?不一定,天知道。
通常情況是沒執行完,那么就是說,當刷新時,數據壓根就沒拉到,這樣的話,你的界面當然不會更新。
public async Task Test(){
await Task.Factory.StartNew(()=>{
//從數據庫拉數據
});
}
改成這樣即可