blazor webapp预呈现导致页面初始化事件复杂化

blazor webapp预呈现导致页面初始化事件复杂化

 

blazor server的页面初始化事件只触发一次,blazor webapp的页面初始化事件会触发两次,如果在页面初始化事件中执行繁忙操作,需要考虑规避多次调用的问题。

 

回顾blazor server的页面初始化事件

VS2022新建一个blazor server项目,就用模板代码,把项目框架改为.net 8。

 WeatherForecastService.cs获取天气预报功能增加延时返回,模拟繁忙任务。

    public async Task<WeatherForecast[]> GetForecastAsync(DateOnly startDate)
    {
        Debug.WriteLine($"{DateTimeOffset.Now:G}, 开始调用繁忙任务");

        await Task.Delay(3000);

        Debug.WriteLine($"{DateTimeOffset.Now:G}, 完成调用繁忙任务");

        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = startDate.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        }).ToArray();
    }

FetchData.razor天气预报页面增加打印调试信息。

    protected override async Task OnInitializedAsync()
    {
        Debug.WriteLine($"{DateTimeOffset.Now:G}, OnInitializedAsync");

        forecasts = await ForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now));
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        Debug.WriteLine($"{DateTimeOffset.Now:G}, OnAfterRenderAsync, firstRender={firstRender}");
    }

调试运行,只触发一次页面初始化事件。

2025/5/5 9:49:03, OnInitializedAsync

2025/5/5 9:49:03, 开始调用繁忙任务

2025/5/5 9:49:03, OnAfterRenderAsync, firstRender=True

2025/5/5 9:49:06, 完成调用繁忙任务

2025/5/5 9:49:06, OnAfterRenderAsync, firstRender=False

 

OnInitializedAsync开始调用繁忙任务,紧接着触发OnAfterRenderAsync,此时是第一次render。

OnInitializedAsync调用繁忙任务结束后,会自动触发一次OnAfterRenderAsync,此时已经不是第一次render。

 

blazor webapp服务器和客户端呈现模式页面初始化事件

新建blazor webapp项目,设为服务器和客户端呈现,每个页面单独呈现。修改模板代码,从ForecastService模块读取天气预报。

 

Weather.razor天气预报页面设为服务器呈现,参考blazor server项目增加打印调试信息。

 

@attribute [StreamRendering]

@rendermode InteractiveServer

 

调试运行,触发了两次页面初始化事件,调用了两次繁忙任务。

2025/5/5 11:01:52, OnInitializedAsync

2025/5/5 11:01:52, 开始调用繁忙任务

2025/5/5 11:01:55, 完成调用繁忙任务

2025/5/5 11:01:55, OnInitializedAsync

2025/5/5 11:01:55, 开始调用繁忙任务

2025/5/5 11:01:55, OnAfterRenderAsync, firstRender=True

2025/5/5 11:01:58, 完成调用繁忙任务

2025/5/5 11:01:58, OnAfterRenderAsync, firstRender=False

 

微软官网对预呈现模式的介绍

Blazor webapp增加了预呈现模式,页面初始化事件行为发生了改变,微软官网有相关的介绍。

https://learn.microsoft.com/zh-cn/aspnet/core/blazor/components/lifecycle?view=aspnetcore-8.0#stateful-reconnection-after-prerendering

在服务器上预呈现时,组件最初作为页面的一部分静态呈现。 浏览器重新建立与服务器的 SignalR 连接后,将再次呈现组件,并且该组件为交互式。 如果存在用于初始化组件的 OnInitialized{Async} 生命周期方法,则该方法执行两次:

l 在静态预呈现组件时执行一次。

l 在建立服务器连接后执行一次。

在最终呈现组件时,这可能导致 UI 中显示的数据发生明显变化。 若要避免此行为,请传递一个标识符以在预呈现期间缓存状态并在预呈现后检索状态。

【示例代码用MemoryCache缓存数据】

 

https://learn.microsoft.com/zh-cn/aspnet/core/blazor/components/prerender?view=aspnetcore-8.0#persist-prerendered-state

为了在预呈现期间保留计数器的初始值,Blazor 支持使用 PersistentComponentState 服务在预呈现页面中保留状态(对于嵌入到 Razor Pages 或 MVC 应用的页面或视图中的组件,使用持久组件状态标记帮助程序)。

若要保留预呈现状态,请决定使用 PersistentComponentState 服务保留什么状态。 PersistentComponentState.RegisterOnPersisting 注册回调以在预呈现期间保留组件状态。 当组件以交互方式呈现时,将检索状态。 在初始化代码结束时进行调用,以避免在应用关闭期间出现潜在的争用条件。

【示例代码用PersistentComponentState缓存数据】

 

blazor webapp服务器呈现模式页面初始化事件

新建blazor webapp项目,设为服务器呈现,所有页面统一呈现,这种设置最接近blazor server。

App.razor

    <Routes @rendermode="InteractiveServer" />

 

修改Weather.razor获取天气预报代码,ForecastService模块读取天气预报,参考blazor server项目增加打印调试信息。

调试运行,只触发一次页面初始化事件,跟blazor server完全一样。

 

结论

对于小型的简单项目,可以使用blazor webapp项目框架,设置为服务器呈现,全局统一,只触发一次页面初始化事件,跟blazor server一样。

假如项目有一些页面需要在客户端呈现,要注意处理两次页面初始化事件的问题,可以参考微软官网的方案。

posted on 2025-05-05 11:45  SunnyTrudeau  阅读(93)  评论(0)    收藏  举报