You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor Server预渲染:如何正确加载数据并更新UI?

解决Blazor组件单次API加载+加载动画显示问题

问题原因分析

  1. OnInitializedAsync请求两次:Blazor Server默认启用预渲染,组件会先在服务器端预渲染一次,客户端连接后再重新渲染一次,导致OnInitializedAsync执行两次,API请求重复。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 23:30:24