今天我们来学习组件的生命周期。
理解组件的生命的周期和生命周期中我们可以编程的方法非常重要,首先要理解组件的基本使命是什么,我们这里讨论的组件实际上就是UI组件,虽然我们可以允许区别有UI呈现的组件和没有UI呈现的组件,但是组件的唯一的使命就是给用户呈现UI并响应用户的交互。那么在整个组件的生命周期中,组件有两个最终的结果,就是渲染和回收,这个两个结果中我们的术语就是Render和Dispose,关于Dispose大家都不陌生,但是对于render我们需要仔细的理解,在本节我们理解它就是将我们需要的内容在浏览器上展现出来,这个就是渲染。
组件生命周期介绍
为了完成我们渲染的目的,Blazor组件定义几个阶段,我们可以这样理解渲染:
当组件第一次渲染:
组件需要注入参数,那么这个阶段我们可以定义和覆盖方法SetParameters或者SetParametersAsync
组件初始化:参数注入成功后,框架调用OnInitialized或者OnInitializedAsync()方法进行初始化,需要注意的是这个阶段组件并没有渲染成功,因此在这个阶段也无法拿到组件的引用。
组件的参数设置: OnParametersSet或者OnParametersSetAsync()这个两个方法,需要注意的是,如果是异步方法,await等待,那么之后等待这个调用完成了后,UI才会进行渲染。
进行渲染,Blazor没有暴漏必要的方法或者callback让我们定制渲染的流程或者决定渲染的组件,这些都由Blazor来控制。
渲染成功后,blazor提供OnAfterRender或者OnAfterRenderAsync事件,需要注意的是这个方法带有一个参数:firstRender,用于表示该组件是否是第一次渲染。另外一个需要注意的是在这个方法调用时,组件已经完成了渲染,除非在这个方法里调用方法:StateHasChange(), 否则在这个方法里对字段,属性等改变,不会引发组件再次渲染,这也是合情理的,否则的话,组件会形成一个渲染的无尽循环。
组件不使用了之后进入Dispose方法,需要注意如果在其他阶段或者其他事件响应方法中添加了委托,那么需要在Dispose方法中移去委托。
组件并不是第一次渲染:
关于什么条件下会导致组件重新渲染,我们下面会讲,但是这里只讲如果不是第一次渲染,组件的生命周期是什么样的。
直接进入组件参数的设置,也即是OnParametersSet或者方法OnParametersSetAsync方法被调用,设置组件参数。
进行渲染
渲染成功后,运行OnAfterRender或者OnAfterRenderAsync方法。
以上是对生命周期的方法的介绍,这里举一个应用的场景,加入您需要和后台通讯获取一个列表的数据,那么需要在哪个生命周期方法里运行代码呢?最好的选择是OnParameterSets这个方法,而且渲染是会等待await,例如我们可以在数据没有拿到之前显示一个进度条,或者loading的字样就可以在这里显示,例如我们在创建一个demo项目是,FetchData这个组件就是这么做的,如下图:
哪些情况会引发组件进行渲染
那么另外一个我们需要理解的是什么情况下组件会渲染呢?
组件第一次被父组件调用时,这个是组件的生命周期中唯一一次强制要渲染的机会。
当组件的组件参数被更新。
当组件中的元素事件被事件句柄被触发。
关于渲染需要注意的几个问题:
生命周期方法OnAfterRender是不会造成组件渲染的,因为这个时候组件已经渲染成功了,但是你可以在该方法中调用StateHashChange主动触发渲染。
如果您覆盖了方法ShouldRender(),并且该方法返回false,那么组件不会渲染(第一次还是渲染,即便返回false)
组件中的元素事件回调函数会自动调用StateHasChanged方法,无需在这些方法里调用这个方法引发组件渲染。
这里我们提到了ShouldRender()这个方法,大家需要注意一下,如果覆盖了这个方法,那么Blazor会根据该方法的返回true orfalse决定是否渲染组件。
关于组件渲染的生命周期的大致的要点我们学习完了,后面的是一些我们技术要点,我们需要注意的事情:
如何在渲染的时候处理异步未完成的任务呢?
很简单,看上述的代码:
需要理解的是渲染也是一个类似while的动作,一直到渲染的生命周期方法OnAfterRender之前。另外也需要注意的是,由其他的地方也会引发重新渲染,可以参考上述,所以我们这里是在OnInitializedAsync方法中处理初始化,同时我们也可以在OnParametersSet{Async}中来处理这个部分。
StateHasChanged()
调用这个方法会触发组件的重新渲染,一定要注意该方法在OnAfterRender方法中的调用,要小心形成渲染死循环。
错误处理:
请参考我们之前的文章,Blazor基础中的错误处理。
关于Blazor Server的预渲染
Blazor Server的配置默认是有预渲染这样一个动作,所谓的预渲染是将组件渲染成静态的页面的形式,当client通过SignalR连接成功后,Blazor Server会再次渲染,并且这里的区别在于预渲染会从SetParametes到OnInitialed,但是不会真的渲染,所以不会有方法OnParametersSet之后的方法,但是重新连接上之后,就会走正常的渲染流程,这样会导致初始化方法被调用两次。
如何判断是在预渲染呢?
可以有两种办法:
定义一个属性或者字段,给定一个默认值,仅仅在OnParameterSet方法及之后的方法里改变这个值。发现这个值没有改变,那么就是在预渲染。
将某些代码移出初始化生命周期方法,并置于OnAfterRender方法中,特别是和JavaScript交互的方法。
我们所有的组件默认情况下是集成自ComponentBase,由ComponentBase定义了组件的生命周期和渲染过程,默认情况下ComponentBase在下述的情况会触发组件渲染:
父组件更新了调用参数。
级联值更新了值(通过级联参数)
组件内的事件通知,(会自动调用StateHasChange)
手动调用StateHasChanged方法。
另外我们上边谈到如果组件的参数改变会引发组件重新渲染,对于组件的参数,我们还有几个约定:
如果组件参数是基本类型,那么只有这些类型改变了,才会渲染。
shouldrender返回false不会渲染。
什么时候我们需要调用StateHasChange()
在一个异步方法中,我们多次进入异步状态,例如:
2. 接收外部的事件,处理完之后。
3. 在渲染树外部进行渲染(例如javascript调用,由javascript直接和odm操作)
AzureDeveloper,一个分享和学习Azure技术的好去处,欢迎关注
领取专属 10元无门槛券
私享最新 技术干货