一、基本理解:首次接触“生命周期”这个名词,是比较晦涩的,Vue中有生命周期钩子,而Blazor则是虚方法重写,容易蒙。所以,我尝试从初学者的角度来阐述一下。
- 我们在基础部分已经知道,组件有两部分组成,一是逻辑层,有数据和方法(方法本质上也是数据);二是视图层,虽然有自定义组件,但拆到底,还是HTML原生标签。
- 组件的初次呈现,可以先简单的理解为两个过程,第一步,完成逻辑层的实例化,类似于一个类的实例化,为视图层准备数据;第二步,完成视图层DOM的渲染,会使用到逻辑层的数据。这个过程,可以认为就是生命周期,当然我们需要继续细化。
- 在这个生命周期中,我们肯定想做两件事情,一是当到达特定阶段时,让我知道,这样我可以执行某些任务;二是我还能根据一些情况的判断,来决定生命周期是否继续执行。
- 为了实现上面的两件事情,Vue为我们准备了不同阶段的生命周期钩子,Blazor则是虚方法。两者的原理是一样的,本质上,是一种命名约定和方法重写。如在完成视图层的DOM渲染后,Vue执行一个名字叫onMounted()的方法,Blazor则执行一个名字叫OnAfterRender()的方法。Vue中,我们使用回调,Blazor中我们通过重写override,就能实现自己想执行的逻辑。
- Blazor的生命周期,使用虚方法和方法重写,有C#基础的会比较容易理解,如果看Blazor生命周期的源码,里面有很多类似这样的代码:if(某某状态出现){则调用某个方法},条件就是用来判断生命周期到哪个阶段了,方法体中调用的方法就是Blazor的生命周期虚方法。而Vue的钩子,虽然易用,但要想理解通透了,则更加晦涩一些。
二、基本使用
两者的使用语法都较简单,直接在逻辑层,按约定写方法就可以。但要使用得当且灵活运用,还是需要了解每一个生命周期过程的细节,尤其是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("[Parameter]参数设置前"); await base.SetParametersAsync(parameters); //收集外部传参到ParameterView,未给[Parameter]参数属性赋值 //最后执行【base.SetParametersAsync】,给[Parameter]参数属性赋值 } protected override void OnInitialized() { Console.WriteLine("组建初始化"); //创建组件实例,完成组件逻辑层的初始化,包括字段、属性等的初始化 //有一个配对的异步函数OnInitializedAsync,如果同步和异步都设置了,则先执行同步,再执行异步 } protected override void OnParametersSet() { Console.WriteLine("参数设置后"); //[Parameter]参数属性更新时执行,当然,首次赋值时也会执行 //OnInitialized只在组件初始化时执行一次,参数更新时,并不执行//有一个配对的异步函数OnParametersSetAsync,如果同步和异步都设置了,则先执行同步,再执行异步 } protected override void OnAfterRender(bool firstRender) { Console.WriteLine("组件渲染后"); //DOM完成渲染后,此时可以获得最新的ref //是否渲染DOM,根据虚拟DOM的差量算法 //可能引起渲染:父组件重新渲染、[Parameter]参数属性变化、本组件字段/属性变化、本组件事件执行等 //有一个配对的异步函数OnAfterRenderAsync,如果同步和异步都设置了,则先执行同步,再执行异步
//回调中可以获得一个布尔类型参数firstRender,如果是首次渲染,则为true,如果不是,则为false
} //Dispose不属于生命函数,所以用法比较特别,先实现IDisposable或IAsyncDisposable接口,然后调用接口的Dispose或DisposeAsync方法 //如果组件使用了非托管资源,比如计时器、导航事件等,必须在Dispose或DisposeAsync方法中释放资源,否则框架会认为组件还在使用,不会回收组件,会造成内存泄露
//IAsyncDisposable相应的调用方法为【public async ValueTask DisposeAsync(){}】
@implements IDisposable @code { public void Dispose() { Console.WriteLine("组件销毁"); } }