Blazor组件中何时需调用StateHasChanged()?二次点击更新问题咨询
问题原因解析
- 核心问题出在
HandleClick方法用了async void作为返回值,Blazor对async void和async Task类型的事件处理方法的生命周期追踪逻辑完全不同。 - Blazor默认的自动渲染规则:普通事件触发后,会在事件处理方法**执行完成后自动调用
StateHasChanged()**刷新页面。对于async void类型的方法,当代码执行到await JSRuntime.InvokeAsync这一行时,方法会立即返回,Blazor会判定事件处理已经完成,立刻触发第一次自动渲染。这时候JS调用还没返回结果,fromJs还没被赋值,所以Part1显示为空。 - 等JS调用异步返回,
fromJs被赋值为返回值的时候,async void的后续执行逻辑已经脱离了Blazor的事件生命周期,Blazor感知不到这次变量更新,不会触发重新渲染,所以第一次点击后页面看不到fromJs的变化,但这时候后台的fromJs变量已经有值了。 - 第二次点击按钮时,Blazor会再次触发事件处理流程,同样在方法执行到
await返回时自动调用StateHasChanged(),这时候上一次点击赋值的fromJs已经有值,所以这次渲染会把旧的fromJs值渲染到页面上,给你造成第二次点击才更新的错觉。
修复方案
把HandleClick的返回值从async void改成async Task即可,Blazor会完整追踪async Task方法的执行周期,等await的JS调用完成、fromJs赋值之后,才会自动触发StateHasChanged(),不需要手动调用也能第一次点击就正常更新Part1的数值。
// 修改后的方法 public async Task HandleClick() { fromJs = await JSRuntime.InvokeAsync<string>("setText", element, "Hello from JS call!"); // 不需要手动调用StateHasChanged() }
内容的提问来源于stack exchange,提问作者popomama
相关产品推荐
相关产品推荐

