Blazor中C#代码移除元素仅生效一次且连接重置问题排查
问题描述
尝试通过单次按钮点击移除div并修改计数器,代码实现如下:
<button @onclick="() => RemoveDocument(className)" class="close-button inner-div">X</button>
private async void RemoveDocument(string className) { AmountOfDocs--; await JSRuntime.InvokeVoidAsync("removeDiv", className); }
function removeDiv(elName) { var element = document.getElementById(elName); element.remove(); }
执行后div确实从DOM中被移除,但出现以下错误,且后续所有按钮无法点击:
blazor.server.js:1 [2023-10-17T14:58:52.607Z] Error: There was an error applying batch 11. blazor.server.js:1 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'removeChild') at H (blazor.server.js:1:17228) at ie.applyEdits (blazor.server.js:1:21401) at ie.updateComponent (blazor.server.js:1:20631) at blazor.server.js:1:115262 at Pn.processBatch (blazor.server.js:1:115634) at kt.<anonymous> (blazor.server.js:1:129816) at blazor.server.js:1:72077 at Array.forEach (<anonymous>) at kt._invokeClientMethod (blazor.server.js:1:72063) at kt._processIncomingData (blazor.server.js:1:70105) [2023-10-17T14:58:52.655Z] Error: System.AggregateException: One or more errors occurred. (TypeError: Cannot read properties of null (reading 'removeChild')) ---> System.InvalidOperationException: TypeError: Cannot read properties of null (reading 'removeChild') at Microsoft.AspNetCore.Components.RenderTree.Renderer.InvokeRenderCompletedCallsAfterUpdateDisplayTask(Task updateDisplayTask, Int32[] updatedComponents) --- End of inner exception stack trace --- log @ blazor.server.js:1 tr @ blazor.server.js:1 (anonymous) @ blazor.server.js:1 (anonymous) @ blazor.server.js:1 _invokeClientMethod @ blazor.server.js:1 _processIncomingData @ blazor.server.js:1 connection.onreceive @ blazor.server.js:1 o.onmessage @ blazor.server.js:1 blazor.server.js:1 [2023-10-17T14:58:52.656Z] Information: Connection disconnected.
问题原因
Blazor Server基于服务器端渲染+SignalR双向通信机制,渲染引擎会维护一份客户端DOM的虚拟映射副本。用JS直接从真实DOM中删除元素后,Blazor的虚拟DOM仍认为该元素存在,后续修改AmountOfDocs触发重新渲染时,引擎尝试操作已被删除的真实DOM节点,就会抛出Cannot read properties of null错误,最终导致SignalR连接断开,所有依赖Blazor交互的按钮失效。
解决方案
放弃JS直接操作DOM的方式,改用Blazor原生的组件渲染逻辑控制元素移除:
- 将需要移除的div包装为组件,通过绑定数据源的方式用
foreach循环渲染 - 点击按钮时直接从数据源中移除对应项,Blazor会自动同步更新真实DOM,同时保证虚拟DOM与真实DOM的一致性
示例代码:
@foreach(var doc in Documents) { <div id="@doc.ClassName"> <!-- 自定义div内容 --> <button @onclick="() => RemoveDocument(doc)">X</button> </div> } <p>文档数量: @Documents.Count</p>
private List<DocumentModel> Documents = new List<DocumentModel>(); private void RemoveDocument(DocumentModel doc) { Documents.Remove(doc); // 无需调用JS,Blazor会自动处理DOM移除 } // 自定义文档模型 public class DocumentModel { public string ClassName { get; set; } // 其他业务属性 }
内容的提问来源于stack exchange,提问作者innom
相关产品推荐
相关产品推荐

