今天要來介紹的是元件的生命週期,了解生命週期才能在元件進行初始化和轉譯期間時執行額外的作業。


這邊先上流程圖,我們再來慢慢說明。

/images/2020-09-28/lifecycle-flow.png

可以看到觸發變更的時間點有三個,父元件渲染到子元件時,使用者行為導致的事件產生,以及父元件將其從渲染樹移除。

而我們能覆寫的生命週期方法有以下四個:

  • 元件初始化方法 (OnInitialized / OnInitializedAsync)

此時間點上,元件已從父元件接收到初始化的參數,只會在 SetParametersAsync 完成後執行一次,絕對不會再次執行。

而當元件屬於頁面元件,也就是使用了 @page 變成可路由元件,如果 URL 不變 blazor 就會重新使用該元件,也就是不會執行 OnInitialized/OnInitializedAsync 且不會觸發 IDisposable.Dispose

  • 設定參數之後 (OnParametersSet / OnParametersSetAsync)

此時間點上,元件已經初始化完成,當 OnInitialized/OnInitializedAsync 執行結束後會執行外,父元件重新渲染並提供新參數時,也會被呼叫。

提供新參數時如果是可變的類型,如自訂類型時,因為 blazor 無法知道參數的內部是否發生變化,所以一律視為已改變;但不可變的類型,則需要至少一個參數改變,才會重新渲染。

  • 防止 UI 重新渲染 (ShouldRender)

再提到 ShouldRender 之前,先提一下它上層的 StateHasChangedStateHasChanged 是不能異動的,用於通知元件其狀態已變更,且所有的 EventCallback 方法都會自動呼叫 StateHasChanged

如果想要避免使用者操作產生的渲染時,可以覆寫此方法來防止 UI 重新渲染,也就是可以確保渲染樹一定是從初始化產生的。

若想進一步了解可以參考ASP.NET Core Blazor WebAssembly 效能最佳做法 - 避免不必要的元件呈現

  • 元件呈現之後 (OnAfterRender / OnAfterRenderAsync)

此時間點上,元件已經完成渲染。此時 DOM 就已經畫好了,如果要使用第三方的 JavaScript 來存取 DOM,就能正確取得了。

而這方法有提供 firstRender 參數,代表是否為第一次渲染,可以確保有些動作只在初始化時執行一次即可。

元件處置

這邊要特別注意的是,如果在元件的生命週期中訂閱事件,請務必在元件移除時進行解除,可以透過實作 IDisposable 來正確釋放資源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@implements IDisposable

...

@code {
private EventHandler<FieldChangedEventArgs> fieldChanged;

protected override void OnInitialized()
{
editContext = new EditContext(...);

fieldChanged = (_, __) =>
{
// ...
};

editContext.OnFieldChanged += fieldChanged;
}

public void Dispose()
{
editContext.OnFieldChanged -= fieldChanged;
}
}

以上就是元件生命週期的介紹,如果想看實際用法可以參考範例程式碼 - Day13

感謝大家的閱讀,我們明天見。

參考資料
ASP.NET Core Blazor 生命週期
Component lifecycles
使用 IDisposable 的元件處置