Blazor循环动态添加Razor图表组件触发lineChart空引用报错
问题根因
空引用的核心原因是Blazor组件@ref引用的赋值时机与数据加载时机不匹配:
- Blazor中通过
@ref捕获的子组件实例,仅会在子组件完成首次渲染挂载后才会被赋值 - 静态写死组件时,页面首次渲染会按顺序完成所有子组件挂载,
lineChart引用正常赋值,后续操作无异常 - foreach动态渲染、或条件渲染新增的组件,若在子组件挂载完成前就调用
DataSetToChartSeries方法,此时lineChart仍为默认null,就会抛出空引用异常 - 现有代码大概率是在
OnParametersSetAsync等渲染前生命周期中直接调用了数据绑定逻辑,动态生成的组件触发参数设置时,内部的LineChart子组件还未完成渲染,引用自然为空。
修复步骤
1. 给动态列表项增加唯一Key
Blazor默认会复用列表渲染的组件实例,易导致引用赋值错乱,给foreach内的每个组件配置唯一@key,保证实例独立渲染:
@foreach (string graphSelector in datasets) { <ChartComponent @key="graphSelector" ViewHeight=50 ViewWidth=80 ColorScheme="Classic20" Multiple=true Items=@(items.Where(p => p.CounterInstance == graphSelector).ToList())> </ChartComponent> }
2. 调整数据加载时机,仅在组件挂载完成后操作图表实例
重写ChartComponent的OnAfterRenderAsync生命周期方法,该方法触发时子组件已经完成渲染,@ref引用已完成赋值:
private bool _isFirstRender = true; private bool _needRefreshData = false; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { _isFirstRender = false; if (_needRefreshData) { await DataSetToChartSeries(); _needRefreshData = false; } } }
3. 兼容参数动态更新场景
如果组件挂载后Items参数会动态变更,在参数变更生命周期中增加引用判断,未挂载时标记待刷新,已挂载时直接加载数据:
protected override async Task OnParametersSetAsync() { if (_isFirstRender) { _needRefreshData = true; return; } await DataSetToChartSeries(); }
4. 增加空值防护
在DataSetToChartSeries入口增加null判断,规避极端时序问题:
private async Task DataSetToChartSeries() { if (lineChart == null) return; // 原有业务逻辑保留 string[] dateLabels = Items.Select(x => x.TimeRun.ToString("yyyy-MM-dd hh:mm")).Distinct().ToArray(); await lineChart.Clear(); await lineChart.AddLabels(dateLabels); if (Multiple) { List<string> graphDatasets = Items.Select(p => p.CounterInstance).Distinct().ToList(); foreach (string graphSelector in graphDatasets) { List<QueryResult> currentDataSet = Items.Where(p => p.CounterInstance == graphSelector).ToList(); await lineChart.AddDataSet(GetLineChartDataset(currentDataSet)); } } else { await lineChart.AddDataSet(GetLineChartDataset(Items)); } await lineChart.Update(); }
注意:不要在
OnInitialized、OnParametersSet这类渲染执行前的生命周期方法中直接操作@ref捕获的子组件,这两个阶段子组件尚未实例化挂载,引用必然为null。
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

