1.blazor组件生命周期
blazor组件生命周期
翻译自: Component lifecycles
blazor组件包含一组虚方法,源码我们可通过重写这些方法来影响应用行为。源码这些方法会在组件生命周期的源码不同阶段执行。以下图展示了生命周期钩子方法的源码执行流程:
SetParametersAsync 方法在每次父组件渲染时执行。
传递给组件的源码参数被包含在ParameterView结构体中。这是源码挂机软件源码分享根据传递到组件的状态对服务器进行异步调用的好时机。
原文:Parameters that were passed into the component are contained in a ParameterView. This 源码is a good point at which to make asynchronous calls to a server (for example) based on the state passed into the component.
在重写的SetParametersAsync中调用base.SetParametersAsync(parameters)时,组件的源码[Parameter]修饰属性会被赋值。
此方法也适合为参数分配默认值,源码更多细节请参考 Optional route parameters。源码
OnInitialized / OnInitializedAsync 方法在为组件的源码[Parameter]属性赋值后执行。与SetParametersAsync类似,源码但可以使用组件状态。源码
这些方法仅在组件创建时执行一次。源码cmo指标源码查询如果父组件稍后更改了组件的源码参数,则这些方法会被跳过。
注意:当组件是一个@page时,且Blazor应用在新的URL下重新渲染此@page,Blazor会重用此@page。因为它是同一个对象,Blazor不会调用IDisposable.Dispose方法,也不会执行OnInitialized方法。
这句话我就没有理解明白,我做了一个实验,一个@page组件有两个路由,一个是/page-one,另一个是麦克支撑压力源码/pageone,那么这两个路由来回跳转的话不单单不会执行OnInitialized,其他的方法也不会执行啊。
OnParametersSet / OnParametersSetAsync 方法在组件的新实例中,在OnInitializedAsync之后立即执行。如果它是一个已存在的组件,因为父组件正在重新呈现,所以OnInitialized*方法会被跳过,而这个方法将在SetParametersAsync之后立即执行。
StateHasChanged 方法会标记组件即将被渲染。
当组件希望通知Blazor发生了可能导致呈现输出不同的更改时,将调用此方法。例如,在一个Clock组件中,github网页源码分享我们可以设置一个循环的1秒计时器,然后执行StateHasChanged以重新呈现正确的时间。
另一个用途是指导Blazor通过异步方法部分地执行重渲染。
ShouldRender 方法可以通过返回false来阻止组件的RenderTree被重新计算。注意,在第一次创建和呈现组件时,不会执行此方法。
例如,当我们知道我们的状态自上次渲染以来没有改变,或者只是以一种会导致相同输出被渲染的方式改变时,指示Blazor不要经过BuildRenderTree过程可以节省处理时间并改善用户体验。
这个方法不会在组件第一次被渲染的时候执行
BuildRenderTree 方法将应呈现给用户的内容放入内存中(虚拟DOM,即RenderTree)。红绿箭头指标源码
上述代码中,向渲染树添加一个h1,内容为“People”。然后它将为people变量中的每个currentPerson局部变量创建一个ShowPersonDetails的新实例。
如果我们的组件在稍后的时间重新渲染,在people中添加一个额外的项,那么ShowPersonDetails组件的一个新实例将被创建并添加到组件的RenderTree中。如果人的条目减少了,那么之前创建的一些ShowPersonDetails组件实例将从组件的RenderTree中被丢弃,如果它们实现了IDisposable, Dispose()将对它们执行。
注意:为了更有效地执行渲染,当在一个循环的上下文中执行渲染时,任何时候都应该添加一个 @key 指令
OnAfterRender / OnAfterRenderAsync 这最后两个方法在Blazor重新生成组件的RenderTree时执行。这可能是由于组件的父组件重新呈现,用户与组件交互(例如鼠标点击),或者组件执行它的StateHasChanged方法来调用重新呈现的结果。
这些方法只有一个名为firstRender的参数。只有在当前组件上第一次调用该方法时,该参数才为true,此后它将始终为false。在需要附加组件连接(例如,通过JavaScript)的情况下,知道这是第一次呈现是很有用的。
只有在OnAfterRender方法执行之后,才可以安全地使用通过@ref指令设置的对组件的引用。
同样的,直到OnAfterRender方法已经执行firstRender设置为true,才可以安全地使用任何通过@ref指令引用的HTML元素集。
Dispose 尽管这不是严格意义上的ComponentBase生命周期方法之一,但如果一个组件实现了IDisposable,那么一旦该组件从其父渲染树中移除,Blazor就会执行Dispose。为了实现IDisposable,我们需要在razor文件中添加@implements IDisposable。
Awaiting within Async lifecycle methods/在异步的生命周期方法中等待
值得注意的是,Blazor将尽可能快地触发渲染,而不是等待长时间运行的异步方法完成后才能呈现组件。
这使得组件能够在执行后台任务(如从服务器检索数据)时为用户呈现内容。
单个方法的等待行为SetParametersAsync
注意:如果重写了该方法,基类的SetParametersAsync方法必须在方法中的任何await指令之前执行,否则将抛出InvalidOperationException。
OnInitializedAsyncOnParametersSetAsyncOnAfterRenderAsync
(记住上述逻辑的一个)简单的规则是SetParametersAsync是唯一不能通过等待任务挂起生命周期进程的方法(观察SetParametersAsync的源码会发现,这个方法中根本就没有await任何东西,所以。。。)。
所有其他异步方法都可以挂起生命周期进程,直到执行退出该方法,而第一个await将导致通过BuildRenderTree进行渲染,以防止用户不得不等待查看更新。
OnRenderAsync可能看起来有些异常,因为它在两种情况下(第一次await时和退出方法时都没有什么动作)都不执行进一步的操作。如果我们考虑到渲染是执行链的最终目标这一事实,那么我们可以将渲染视作是执行链的最终结果,而不是什么都不做。至于在await上渲染,如果需要,那么程序员必须通过调用StateHasChanged来显式地完成(这个方法中调用StateHasChanged,我实在想不出什么场景能够做这样的操作,关键是容易出现渲染无限循环),否则OnAfterRenderAsync中将导致一个无限循环。
OnAfterRenderAsync这个方法在ComponentBase的源码中它直接了Task.CompletedTask
异步方法和多个await
在async方法中,Blazor执行的代码只会在第一次等待时执行。随后的await不会导致多个渲染。例如
上述例子是原文中的,可能并不好懂,我们来写一个更好懂的:
在上述代码中,如果我没有添加任何StateHasChanged()的话,那么在整个方法结束时页面上会输出_count的值是3,但是中间的变化过程会被忽略掉。
如果我们想要在额外的点上呈现,那么我们必须在所有额外的await语句之前调用StateHasChanged。
有关如何在同一组件上运行不同线程时安全工作的更多信息,请参阅多线程呈现一节。Multi-threaded rendering.