Blazor Server预渲染:如何正确加载数据并更新UI?
解决Blazor组件单次API加载+加载动画显示问题
问题原因分析
- OnInitializedAsync请求两次:Blazor Server默认启用预渲染,组件会先在服务器端预渲染一次,客户端连接后再重新渲染一次,导致
OnInitializedAsync执行两次,API请求重复。 - OnAfterRenderAsync无法显示加载动画:设置
isLoading=true后没有立即调用StateHasChanged()触发UI更新,await API请求期间UI不会刷新,等请求完成后才一起更新状态,导致加载动画无法显示。
正确实现方案
方案1:禁用预渲染(简单直接)
如果不需要预渲染,直接在页面或组件上禁用,确保OnInitializedAsync只执行一次,同时正确触发加载状态更新。
组件代码
public class MyComponent : ComponentBase { private bool isLoading; private List<MyData> myData; [Inject] private IMyService _myService { get; set; } // 确保服务已通过依赖注入注入 protected override async Task OnInitializedAsync() { isLoading = true; // 立即通知组件更新UI,显示加载动画 StateHasChanged(); try { myData = await _myService.GetDataAsync(); } finally { // 无论请求成功/失败,都关闭加载状态 isLoading = false; } } }
页面禁用预渲染
在使用组件的页面中添加渲染模式设置:
@page "/my-page" @rendermode="InteractiveServer(prerender: false)" <MyComponent />
方案2:保留预渲染,避免重复请求
如果需要预渲染优化首屏体验,可通过判断预渲染状态,仅在客户端交互阶段请求数据。
组件代码(.NET 7+)
public class MyComponent : ComponentBase { private bool isLoading; private List<MyData> myData; [Inject] private IMyService _myService { get; set; } private bool _dataLoaded; protected override async Task OnInitializedAsync() { // IsPrerendering是.NET 7+提供的属性,直接判断是否处于预渲染阶段 if (!IsPrerendering && !_dataLoaded) { isLoading = true; StateHasChanged(); try { myData = await _myService.GetDataAsync(); _dataLoaded = true; } finally { isLoading = false; } } } }
UI渲染部分
在组件的razor视图中添加加载动画和数据展示逻辑:
@if (isLoading) { <div style="padding: 20px; text-align: center;"> <span class="spinner-border spinner-border-sm"></span> 加载中... </div> } else if (myData?.Any() == true) { <ul class="list-group"> @foreach (var item in myData) { <li class="list-group-item">@item.Id - @item.Name</li> } </ul> } else if (!isLoading) { <div class="alert alert-info">暂无数据</div> }
关键注意事项
- 调用
await前必须手动调用StateHasChanged(),否则设置的isLoading=true不会立即触发UI更新,加载动画无法显示。 - 使用
try-finally确保加载状态最终关闭,避免API请求出错后页面一直停留在加载状态。 - 预渲染场景下,必须通过状态标志(如
_dataLoaded)避免重复请求数据。
内容的提问来源于stack exchange,提问作者jeb
相关产品推荐
相关产品推荐

