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

Blazor子组件属性渲染异常:父页面首次加载无法获取正确值

问题:Blazor父页面首次渲染无法获取子组件正确属性值

编写Blazor封装组件时,遇到父页面首次渲染无法正确读取子组件属性值的问题,简化示例如下:

子组件(RBTest)

<div class="col-2"> <input @bind="TotalRows"></input> Total Rows</div>
<div class="col-2"> @TotalRows Total Rows</div>
<div class="col-2"> @GetRows() Total Rows</div>

@code {
    public DataTable dtFull = new DataTable();        
    public int TotalRows { get; set; } = 0;   

    public RBTest() { }

    public RBTest(RBDataTable i_RBDT)
    {        
        dtFull = i_RBDT.ReadAllDetails(); //数据访问层方法
        TotalRows = dtFull.Rows.Count;
    }

    public int GetRows()
    {
        return TotalRows;
    }    
}

父页面

<PageTitle>Index</PageTitle>

<RBTest @ref="Test"></RBTest>
<div>@Test.GetRows()</div>

@code 
{
    RBTest Test = new RBTest(); //Blazor组件实例
    T_DIV_DIVIDEND Data = new T_DIV_DIVIDEND(); //数据访问层对象,暂忽略

    protected override async Task OnInitializedAsync()
    {
        Test  = new RBTest(Data.RBDT);        
    }
}

现象

子组件内部的TotalRows值显示正确,但父页面首次渲染时调用Test.GetRows()返回0。

原因

核心问题是手动实例化组件与Blazor框架管理的组件实例不一致:

  • 父页面中@ref="Test"绑定的是Blazor框架渲染时创建的子组件实例,而非手动new的实例。
  • 首次渲染时,父页面使用的是初始new RBTest()的实例(TotalRows为0),而OnInitializedAsync中重新赋值的Test实例并未关联到UI上的子组件,框架也不会渲染这个手动创建的实例。

解决方案

1. 遵循Blazor组件规范:用参数传递数据,弃用自定义构造函数

Blazor组件不推荐通过自定义构造函数接收数据,标准方式是通过[Parameter]属性传递参数,并在生命周期方法中初始化数据。

修改后的子组件:

<div class="col-2"> <input @bind="TotalRows"></input> Total Rows</div>
<div class="col-2"> @TotalRows Total Rows</div>
<div class="col-2"> @GetRows() Total Rows</div>

@code {
    private DataTable dtFull = new DataTable();        
    public int TotalRows { get; set; } = 0;   

    // 用参数接收外部传入的数据
    [Parameter]
    public RBDataTable RBDT { get; set; }

    // 参数更新时初始化数据
    protected override void OnParametersSet()
    {
        if (RBDT != null)
        {
            dtFull = RBDT.ReadAllDetails();
            TotalRows = dtFull.Rows.Count;
        }
    }

    public int GetRows()
    {
        return TotalRows;
    }    
}

2. 父页面正确管理组件实例,依赖框架赋值@ref

父页面不再手动创建组件实例,由Blazor框架通过@ref赋值,并确保在组件渲染完成后再访问实例。

修改后的父页面:

<PageTitle>Index</PageTitle>

<!-- 通过参数传递数据给子组件 -->
<RBTest @ref="Test" RBDT="Data.RBDT"></RBTest>
<!-- 空引用保护,避免首次渲染时Test未赋值导致报错 -->
<div>@(Test?.GetRows() ?? 0)</div>

@code 
{
    // 仅声明变量,由框架赋值
    private RBTest Test;
    private T_DIV_DIVIDEND Data = new T_DIV_DIVIDEND();

    protected override async Task OnInitializedAsync()
    {
        // 如果Data.RBDT需要异步加载,在此完成初始化
        // await Data.LoadRBDTAsync();
        // 异步操作后通知框架重新渲染
        StateHasChanged();
    }

    // 首次渲染完成后,安全访问子组件实例
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            // 此时Test已被框架赋值,可以正常调用方法
            var rowCount = Test.GetRows();
            // 执行后续逻辑
        }
    }
}

关键修改点

  • 子组件移除自定义构造函数,改用[Parameter]接收数据,在OnParametersSet中初始化属性,符合Blazor生命周期规范。
  • 父页面不再手动实例化组件,@ref由框架在组件渲染完成后赋值。
  • 使用Test?.GetRows() ?? 0避免首次渲染时的空引用异常。
  • 如需在首次渲染后操作子组件,在OnAfterRenderAsync的firstRender分支中处理,确保组件实例已就绪。

内容的提问来源于stack exchange,提问作者Richard Barker

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 01:30:06