Blazor foreach循环内如何逐个渲染子组件并实时更新UI?
解决方案
Blazor默认会批量处理同步执行过程中的所有UI更新请求,你在同步循环内调用StateHasChanged()时,所有的状态变更通知都会被合并,直到整个方法执行完成后才会触发一次完整渲染,这就是你之前无法实现逐个渲染的核心原因,死循环也是同步模式下重复触发状态更新导致的。
你可以把列表填充逻辑改成异步流程,每次添加完一个列表项后让出线程,让Blazor有机会完成当前的UI渲染后再处理下一项,修改后的Main.razor代码如下:
@foreach (Vehicle vehicle in _vehicles) { if (vehicle.Visible) { <VehicleComponent Vehicle=@vehicle></VehicleComponent> } } @code { private List<Vehicle> _vehicles = new(); protected override async Task OnInitializedAsync() { // 替换为你自己的全量车辆数据源获取逻辑 var allVehicleData = GetTotalVehicleList(); foreach (var vehicle in allVehicleData) { _vehicles.Add(vehicle); StateHasChanged(); // 让出线程,让Blazor完成本次UI渲染再继续执行 await Task.Yield(); } } // 示例方法,替换为你实际获取全量车辆数据的逻辑 private List<Vehicle> GetTotalVehicleList() { // 这里返回你原本要填充到_vehicles的所有车辆数据 return new List<Vehicle>(); } }
原理解释
await Task.Yield()会强制异步方法立刻返回控制权给调用方,Blazor就可以在这个间隙处理挂起的渲染任务,把刚加入列表的单个车辆组件渲染完成后,再回到循环中处理下一个列表项。- 如果单组件渲染成本较高,也可以将
Task.Yield()替换为await Task.Delay(1),给渲染预留更充足的时间,大多数场景下Task.Yield()就能满足需求。 - 如果你的车辆数据本身就是从远程接口逐个拉取的,只需要每拉取到一条数据就添加到
_vehicles列表,调用StateHasChanged()后加一句await Task.Yield()即可,无需提前拿到全量数据。
内容的提问来源于stack exchange,提问作者Dagovax
相关产品推荐
相关产品推荐

