Blazor 框架包括同步和异步生命周期方法。 重写生命周期方法,以便在组件初始化和呈现期间对组件执行其他操作。
当组件从其父组件收到其初始参数后,将调用 OnInitializedAsync 和 OnInitialized。 当组件执行异步操作时,请使用 OnInitializedAsync
,并在操作完成时进行刷新。
对于同步操作,请重写 OnInitialized
:
protected override void OnInitialized() { ... }
若要执行异步操作,请重写 OnInitializedAsync
,并对操作使用 await
关键字:
protected override async Task OnInitializedAsync() { await ... }
Blazor Server apps 预呈现其内容调用 OnInitializedAsync
两次 :
若要防止 OnInitializedAsync
中的开发人员代码运行两次,请参阅预呈现后的有状态重新连接部分。
在预呈现 Blazor 服务器应用时,某些操作(如调用 JavaScript)不可能,因为尚未建立与浏览器的连接。 在预呈现时,组件可能需要以不同的方式呈现。 有关详细信息,请参阅检测应用程序何时预呈现部分。
SetParametersAsync 设置由呈现树中的组件父级提供的参数:
public override async Task SetParametersAsync(ParameterView parameters) { await ... await base.SetParametersAsync(parameters); }
ParameterView 包含每次调用 SetParametersAsync
时的完整参数值集。
SetParametersAsync
的默认实现将每个属性的值设置为在 ParameterView
中具有相应值的 [Parameter]
或 [CascadingParameter]
特性。 在 ParameterView
中没有相应值的参数将保持不变。
如果未调用 base.SetParametersAync
,则自定义代码可以通过任何所需的方式解释传入参数值。 例如,不要求将传入参数分配给类的属性。
调用 OnParametersSetAsync 和 OnParametersSet:
protected override async Task OnParametersSetAsync() { await ... }
备注
应用参数和属性值时的异步工作必须在 OnParametersSetAsync
生命周期事件期间发生。
protected override void OnParametersSet() { ... }
当组件完成呈现后,将调用 OnAfterRenderAsync 和 OnAfterRender。 此时将填充元素和组件引用。 使用此阶段,可以使用呈现的内容来执行其他初始化步骤,如激活在呈现的 DOM 元素上操作的第三方 JavaScript 库。
OnAfterRenderAsync
和 OnAfterRender
的 firstRender
参数:
true
。protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { await ... } }
备注
在 OnAfterRenderAsync
生命周期事件期间,必须立即进行渲染后的异步工作。
即使从 OnAfterRenderAsync
中返回 Task,该任务完成后,框架也不会为组件计划进一步的呈现循环。 这是为了避免出现无限的呈现循环。 它与其他生命周期方法不同,后者将在返回的任务完成后计划更多的渲染循环。
protected override void OnAfterRender(bool firstRender) { if (firstRender) { ... } }
在服务器上预呈现时不会调用OnAfterRender
和 OnAfterRenderAsync
。
重写 ShouldRender 以取消 UI 刷新。 如果实现返回 true
,则将刷新 UI:
protected override bool ShouldRender() { var renderUI = true; return renderUI; }
每次呈现组件时,都将调用 ShouldRender
。
即使 ShouldRender
被重写,组件也始终是最初呈现的。
StateHasChanged 通知组件状态已更改。 如果适用,调用 StateHasChanged
会导致组件重新呈现。
在呈现组件之前,在生命周期事件中执行的异步操作可能尚未完成。 在执行生命周期方法时,对象可能 null
或未完全填充数据。 提供呈现逻辑以确认对象已初始化。 null
对象时呈现占位符 UI 元素(例如,加载消息)。
在 Blazor 模板的 FetchData
组件中,OnInitializedAsync
被重写为 asychronously 接收预测数据(forecasts
)。 null``forecasts
时,将向用户显示一条加载消息。 OnInitializedAsync
的 Task
返回完成后,组件将重新呈现已更新状态。
页面/FetchData Blazor 服务器模板:
@page "/fetchdata" @using MyBlazorApp.Data @inject WeatherForecastService ForecastService <h1>Weather forecast</h1> <p>This component demonstrates fetching data from a service.</p> @if (_forecasts == null) { <p><em>Loading...</em></p> } else { <table class="table"> <!-- forecast data in table element content --> </table> } @code { private WeatherForecast[] _forecasts; protected override async Task OnInitializedAsync() { _forecasts = await ForecastService.GetForecastAsync(DateTime.Now); } }
如果某个组件实现 IDisposable,则在从 UI 中删除该组件时,将调用Dispose 方法。 以下组件使用 @implements IDisposable
和 Dispose
方法:
@using System @implements IDisposable ... @code { public void Dispose() { ... } }
备注
不支持在 Dispose
中调用 StateHasChanged。 StateHasChanged
可以作为撕裂渲染器的一部分被调用,因此不支持在该点请求 UI 更新。
有关在执行生命周期方法期间处理错误的信息,请参阅 处理 ASP.NET Core Blazor 应用中的错误。
当 RenderMode
ServerPrerendered
时,在 Blazor Server 应用程序中,最初以页面的形式呈现组件。 一旦浏览器与服务器建立了连接,该组件将再次呈现,并且该组件现在是交互式的。 如果存在用于初始化组件的OnInitialized {Async}生命周期方法,则将执行两次此方法:
这可能会导致在最终呈现组件时,UI 中显示的数据发生显著变化。
若要避免 Blazor 服务器应用中出现双重渲染方案:
下面的代码演示基于模板的 Blazor 服务器应用中的更新 WeatherForecastService
,可避免双重呈现:
public class WeatherForecastService { private static readonly string[] _summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; public WeatherForecastService(IMemoryCache memoryCache) { MemoryCache = memoryCache; } public IMemoryCache MemoryCache { get; } public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate) { return MemoryCache.GetOrCreateAsync(startDate, async e => { e.SetOptions(new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30) }); var rng = new Random(); await Task.Delay(TimeSpan.FromSeconds(10)); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = startDate.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = _summaries[rng.Next(_summaries.Length)] }).ToArray(); }); } }
有关 RenderMode
的详细信息,请参阅 ASP.NET Core Blazor 宿主模型配置。
在预呈现 Blazor 服务器应用时,某些操作(如调用 JavaScript)不可能,因为尚未建立与浏览器的连接。 在预呈现时,组件可能需要以不同的方式呈现。
若要在建立与浏览器的连接后延迟 JavaScript 互操作调用,可以使用OnAfterRenderAsync 组件生命周期事件。 仅在完全呈现应用并建立客户端连接后,才调用此事件。
@using Microsoft.JSInterop @inject IJSRuntime JSRuntime <div @ref="divElement">Text during render</div> @code { private ElementReference divElement; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { await JSRuntime.InvokeVoidAsync( "setElementText", divElement, "Text after render"); } } }
对于前面的示例代码,请在wwwroot/index.html (Blazor WebAssembly)或Pages/_Host (Blazor Server)的 <head>
元素内提供 setElementText
JavaScript 函数。 使用 IJSRuntime.InvokeVoidAsync
调用函数,并且不返回值:
<script> window.setElementText = (element, text) => element.innerText = text; </script>
警告
前面的示例仅修改了文档对象模型(DOM),以便仅用于演示目的。 大多数情况下不建议使用 JavaScript 直接修改 DOM,因为 JavaScript 可能会干扰 Blazor的更改跟踪。
以下组件演示了如何以与预呈现兼容的方式将 JavaScript 互操作作为组件的初始化逻辑的一部分使用。 该组件显示可以从 OnAfterRenderAsync
内触发呈现更新。 开发人员必须避免在此方案中创建无限循环。
在调用 JSRuntime.InvokeAsync
的情况下,ElementRef
仅用于 OnAfterRenderAsync
,而不是在任何早期的生命周期方法中,因为在呈现组件之前,不会有 JavaScript 元素。
调用StateHasChanged以诸如此类组件,并将新状态从 JavaScript 互操作调用中获取。 此代码不会创建无限循环,因为仅当 infoFromJs
null
时才会调用 StateHasChanged
。
@page "/prerendered-interop" @using Microsoft.AspNetCore.Components @using Microsoft.JSInterop @inject IJSRuntime JSRuntime <p> Get value via JS interop call: <strong id="val-get-by-interop">@(infoFromJs ?? "No value yet")</strong> </p> Set value via JS interop call: <div id="val-set-by-interop" @ref="divElement"></div> @code { private string infoFromJs; private ElementReference divElement; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender && infoFromJs == null) { infoFromJs = await JSRuntime.InvokeAsync<string>( "setElementText", divElement, "Hello from interop call!"); StateHasChanged(); } } }
对于前面的示例代码,请在wwwroot/index.html (Blazor WebAssembly)或Pages/_Host (Blazor Server)的 <head>
元素内提供 setElementText
JavaScript 函数。 使用 IJSRuntime.InvokeAsync
调用函数并返回值:
<script> window.setElementText = (element, text) => { element.innerText = text; return text; }; </script>
警告
前面的示例仅修改了文档对象模型(DOM),以便仅用于演示目的。 大多数情况下不建议使用 JavaScript 直接修改 DOM,因为 JavaScript 可能会干扰 Blazor的更改跟踪。