Blazor和Vue對比學習(進階2.1.1):生命週期,基本理解和使用

functionMC 發表於 2022-05-21
Vue

一、基本理解

首次接觸“生命週期”這個名詞,是比較晦澀的,Vue中又有生命週期鉤子,而Blazor則是虛方法重寫,容易蒙。所以,我嘗試從初學者的角度來闡述一下。

1、我們在基礎部分已經知道,元件有兩部分組成,一是邏輯層,有資料和方法(方法本質上也是資料);二是檢視層,雖然有自定義元件,但拆到底,還是HTML原生標籤。

2、元件的初次呈現,可以先簡單的理解為兩個過程,第一步,完成邏輯層的例項化,類似於一個類的例項化,為檢視層準備資料;第二步,完成檢視層DOM的渲染,會使用到邏輯層的資料。這就是生命週期,當然中間過程我們需要繼續細化。

3、在這個生命週期中,我們肯定想做兩件事情,一是當到達特定階段時,讓我知道,這樣我可以執行某些任務;二是我還能根據一些情況的判斷,來決定生命週期是否繼續執行。

4、為了實現上面的兩件事情,Vue為我們準備了不同階段的生命週期鉤子,Blazor則是虛方法。兩者的原理是一樣的,本質上,是一種命名約定和方法重寫。如在完成檢視層的DOM渲染後,Vue執行一個名字叫onMounted()的方法,Blazor則執行一個名字叫OnAfterRender()的方法。Vue中,我們使用回撥,Blazor中我們通過重寫override,就能實現自己想執行的邏輯。

5、Blazor生命週期的使用,更加接近於本質,虛方法和方法重寫,有C#基礎的,都好理解,而Vue的鉤子,雖然易用,但要想整通透了,則更加晦澀一些。如果看Blazor生命週期的原始碼,裡面有很多類似這樣的程式碼:if(某某狀態出現){則呼叫某個方法},條件就是用來判斷生命週期到哪個階段了,方法體中呼叫的方法就是Blazor的生命週期虛方法,是不是很容易理解?!

 

二、基本使用

兩者的語法使用都非常簡單,直接在邏輯層,按約定寫方法就可以。但要使用得當且靈活運用,還是需要了解每一個生命週期過程的細節,尤其是Blazor,會相對複雜一些。Blazor提供了更加豐富的控制方法,但也提高了使用的複雜度,看產品路線圖,未來還會繼續增加生命函式。對生命週期細節更深入的學習,我們放到第二節,這節先簡單瞭解一下

1、 Vue的生命週期鉤子,作為API匯入,方法體中寫回撥邏輯。

//Vue=======================================

onBeforeMount(()=>{console.log("元件渲染/掛載前")})
onMounted(()=>{console.log('元件渲染/掛載後')})

onBeforeUpdate(()=>{console.log('資料更新前')})
onUpdated(()=>{console.log('資料更新後')})

onBeforeUnmount(()=>{console.log('元件銷燬前')})
onUnmounted(()=>{console.log('元件銷燬後')})

 

2、Blazor直接重寫生命週期函式(方法簽名一致),方法體中寫自己的邏輯,部分虛擬函式提供了入參

//Blazor====================================

public override async Task SetParametersAsync(ParameterView parameters)
{
    Console.WriteLine("引數設定前"); 
    await base.SetParametersAsync(parameters);  
    //完成內部欄位/屬性的初始化,收集外部傳引數到ParameterView,未給引數屬性賦值
    //最後執行【base.SetParametersAsync】,給引數屬性賦值
}

protected override void OnInitialized()
{
    Console.WriteLine("組建初始化"); 
    //建立元件例項,完成元件的初始化,此時引數屬性已被賦值
    //有一個配對的非同步函式OnInitializedAsync
}

protected override void OnParametersSet()
{
    Console.WriteLine("引數設定後"); 
    //這個生命函式更像是OnInitialized的備胎
    //OnInitialized只在元件初始化時執行一次,引數更新時,並不執行
    //所以需要一個生命函式來完成OnInitialized做的事情
    //有一個配對的非同步函式OnParametersSetAsync
}

protected override void OnAfterRender(bool firstRender)
{
    Console.WriteLine("元件渲染後"); 
    //DOM完成渲染後,此時可以獲得最新的ref
    //是否渲染DOM,根據虛擬DOM的差量演算法
    //可能引起渲染:父元件重新渲染、父元件傳入的引數屬性變化、本元件欄位/屬性變化、本元件事件執行等
    //有一個配對的非同步函式OnAfterRenderAsync
}

//Dispose不屬於生命函式,所以用法比較特別,先實現IDisposable介面,然後呼叫介面的Dispose方法
//這個設計比較奇怪的,也沒有查到這麼設計的原因,推斷是防止重複執行,因為Dispose是框架層級的一個方法
@implements IDisposable
@code {
  void IDisposable.Dispose()
  {
    Console.WriteLine("元件銷燬");
  }
}