Skip to main content

Blazor组件基础之生命周期和渲染

分类:  Blazor入门 标签:  #Asp.Net core基础 #.Net #Web #Web Client #Blazor 发布于: 2023-05-27 16:16:12

今天我们来学习组件的生命周期。

理解组件的生命的周期和生命周期中我们可以编程的方法非常重要,首先要理解组件的基本使命是什么,我们这里讨论的组件实际上就是UI组件,虽然我们可以允许区别有UI呈现的组件和没有UI呈现的组件,但是组件的唯一的使命就是给用户呈现UI并响应用户的交互。那么在整个组件的生命周期中,组件有两个最终的结果,就是渲染和回收,这个两个结果中我们的术语就是RenderDispose, 关于Dispose大家都不陌生,但是对于render我们需要仔细的理解,在本节我们理解它就是将我们需要的内容在浏览器上展现出来,这个就是渲染。

 

组件生命周期介绍

为了完成我们渲染的目的,Blazor组件定义几个阶段,我们可以这样理解渲染:

  1. 当组件第一次渲染:

    1. 组件需要注入参数,那么这个阶段我们可以定义和覆盖方法SetParameters或者SetParametersAsync

    2. 组件初始化:参数注入成功后,框架调用OnInitialized或者OnInitializedAsync()方法进行初始化,需要注意的是这个阶段组件并没有渲染成功,因此在这个阶段也无法拿到组件的引用。

    3. 组件的参数设置:      OnParametersSet或者OnParametersSetAsync() 这个两个方法,需要注意的是,如果是异步方法,await等待,那么之后等待这个调用完成了后,UI才会进行渲染。

    4. 进行渲染,Blazor没有暴漏必要的方法或者callback让我们定制渲染的流程或者决定渲染的组件,这些都由Blazor来控制。

    5. 渲染成功后,blazor提供OnAfterRender或者OnAfterRenderAsync事件,需要注意的是这个方法带有一个参数:firstRender, 用于表示该组件是否是第一次渲染。另外一个需要注意的是在这个方法调用时,组件已经完成了渲染,除非在这个方法里调用方法:StateHasChange(),      否则在这个方法里对字段,属性等改变,不会引发组件再次渲染,这也是合情理的,否则的话,组件会形成一个渲染的无尽循环。

    6. 组件不使用了之后进入Dispose方法,需要注意如果在其他阶段或者其他事件响应方法中添加了委托,那么需要在Dispose方法中移去委托。

  2. 组件并不是第一次渲染:
             关于什么条件下会导致组件重新渲染,我们下面会讲,但是这里只讲如果不是第一次渲染,组件的生命周期是什么样的。

    1. 直接进入组件参数的设置,也即是OnParametersSet或者方法OnParametersSetAsync方法被调用,设置组件参数。

    2. 进行渲染

    3. 渲染成功后,运行OnAfterRender或者OnAfterRenderAsync方法。

 

以上是对生命周期的方法的介绍,这里举一个应用的场景,加入您需要和后台通讯获取一个列表的数据,那么需要在哪个生命周期方法里运行代码呢?最好的选择是OnParameterSets{Async} 这个方法,而且渲染是会等待await 例如我们可以在数据没有拿到之前显示一个进度条,或者loading的字样就可以在这里显示,例如我们在创建一个demo项目是,FetchData这个组件就是这么做的,如下图:



哪些情况会引发组件进行渲染

那么另外一个我们需要理解的是什么情况下组件会渲染呢?

  1. 组件第一次被父组件调用时,这个是组件的生命周期中唯一一次强制要渲染的机会。

  2. 当组件的组件参数被更新。

  3. 当组件中的元素事件被事件句柄被触发。

关于渲染需要注意的几个问题:

  1. 生命周期方法OnAfterRender{Async} 是不会造成组件渲染的,因为这个时候组件已经渲染成功了,但是你可以在该方法中调用StateHashChange 主动触发渲染。

  2. 如果您覆盖了方法ShouldRender(), 并且该方法返回false, 那么组件不会渲染(第一次还是渲染,即便返回false)

  3. 组件中的元素事件回调函数会自动调用StateHasChanged方法,无需在这些方法里调用这个方法引发组件渲染。

这里我们提到了ShouldRender()这个方法,大家需要注意一下,如果覆盖了这个方法,那么Blazor会根据该方法的返回true or false 决定是否渲染组件。

关于组件渲染的生命周期的大致的要点我们学习完了,后面的是一些我们技术要点,我们需要注意的事情:

如何在渲染的时候处理异步未完成的任务呢?

很简单,看上述的代码:


需要理解的是渲染也是一个类似while的动作,一直到渲染的生命周期方法OnAfterRender之前。另外也需要注意的是,由其他的地方也会引发重新渲染,可以参考上述,所以我们这里是在OnInitializedAsync方法中处理初始化,同时我们也可以在OnParametersSet{Async}中来处理这个部分。


StateHasChanged()

调用这个方法会触发组件的重新渲染,一定要注意该方法在OnAfterRender方法中的调用,要小心形成渲染死循环。

错误处理:

请参考我们之前的文章, Blazor基础之错误处理

 

关于Blazor Server的预渲染

Blazor Server的配置默认是有预渲染这样一个动作,所谓的预渲染是将组件渲染成静态的页面的形式,当client通过SignalR连接成功后,Blazor Server会再次渲染,并且这里的区别在于预渲染会从SetParametes OnInitialed,但是不会真的渲染,所以不会有方法OnParametersSet之后的方法,但是重新连接上之后,就会走正常的渲染流程,这样会导致初始化方法被调用两次。

如何判断是在预渲染呢?

可以有两种办法:

  1. 定义一个属性或者字段,给定一个默认值,仅仅在OnParameterSet方法及之后的方法里改变这个值。发现这个值没有改变,那么就是在预渲染。

  2. 将某些代码移出初始化生命周期方法,并置于OnAfterRender方法中,特别是和JavaScript交互的方法。

我们所有的组件默认情况下是集成自ComponentBase,ComponentBase定义了组件的生命周期和渲染过程,默认情况下ComponentBase在下述的情况会触发组件渲染:

  • 父组件更新了调用参数。

  • 级联值更新了值(通过级联参数)

  • 组件内的事件通知,(会自动调用StateHasChange)

  • 手动调用StateHasChanged方法。

另外我们上边谈到如果组件的参数改变会引发组件重新渲染,对于组件的参数,我们还有几个约定:

  1. 如果组件参数是基本类型,那么只有这些类型改变了,才会渲染。

  2. shouldrender返回false不会渲染。


什么时候我们需要调用StateHasChange()

  1. 在一个异步方法中,我们多次进入异步状态,例如:

  2. 接收外部的事件,处理完之后。

  3.  在渲染树外部进行渲染(例如javascript调用,由javascript直接和odm操作)