Blazor Server后台更新值浏览器不刷新:原因及优化疑问
Blazor Server Counter组件定时器更新与StateHasChanged的疑问
先看默认的Counter组件代码,点击按钮能正常更新计数并刷新页面:
<p role="status">Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
但改成用后台定时器更新计数时,页面不会自动刷新最新数值,只有点击按钮后才会展示:
@code { private int currentCount = 0; protected async override Task OnInitializedAsync() { var timer = new PeriodicTimer(TimeSpan.FromSeconds(1)); while (await timer.WaitForNextTickAsync()) { currentCount++; } await base.OnInitializedAsync(); } private void IncrementCount() { currentCount++; } }
手动添加StateHasChanged()调用就能解决这个问题:
while (await timer.WaitForNextTickAsync()) { currentCount++; StateHasChanged(); }
针对这里的两个疑问,解答如下:
疑问1:调用StateHasChanged()是否会导致整个组件重渲染,造成性能浪费?
- Blazor用的是差异渲染机制,不是全量重渲染。调用
StateHasChanged()后,Blazor会对比组件当前的渲染树和新生成的渲染树,只更新DOM中实际发生变化的部分——比如这个Counter组件里,只有显示currentCount的文本节点会被更新,其他DOM元素不会动。 - 对于Counter这种简单组件,哪怕真的全量重渲染,性能开销也可以忽略不计;但如果是复杂组件且频繁触发渲染,可以通过重写
ShouldRender()方法来控制渲染时机,比如只有当currentCount变化时才返回true,避免不必要的渲染触发。
疑问2:为何点击事件的IncrementCount方法无需调用StateHasChanged()?
- Blazor会自动处理框架内置的事件(比如
@onclick、@oninput这类):在这些事件的处理方法执行完毕后,框架会自动调用一次StateHasChanged(),触发组件的渲染更新。 - 而定时器的回调属于自定义的后台异步任务,不在Blazor自动触发渲染的机制覆盖范围内,所以必须手动调用
StateHasChanged()来通知框架:组件状态已经变更,需要更新UI了。
内容的提问来源于stack exchange,提问作者mxmissile
相关产品推荐
相关产品推荐

