何时在 Blazor 组件中调用 StateHasChanged()
Posted
技术标签:
【中文标题】何时在 Blazor 组件中调用 StateHasChanged()【英文标题】:when to call StateHasChanged() in Blazor component 【发布时间】:2021-11-07 03:53:32 【问题描述】:我想弄清楚何时需要调用 StateHasChanged()。我知道通过 javascript 更改值时,可能需要强制 blazor 组件呈现页面。在下面的代码中,我有一个名为 HandleClick 的方法来处理按钮单击,我故意注释掉 StateHasChanged() 。 HandleClick 方法本身调用Javascript 来设置Part 2 中元素的值。由于 Blazor 组件不知道 fromJs 值的变化,所以 Part 1 中的值在点击后不会更新。但问题是为什么当我再次单击按钮时 Part 1 中的值会发生变化。
@page "/ExampleY"
@using Microsoft.AspNetCore.Components
@using Microsoft.JSInterop
@inject IJSRuntime JSRuntime
<div class="p-2">
<p class="alert-info p-3">
Part 1. Get value via JS call: <strong>@(fromJs ?? "Empty")</strong>
</p>
<p class="alert-success p-3">
Part 2. Set value via JS call: <strong @ref="element"></strong>
</p>
<button class="btn btn-success" @onclick="HandleClick">Click to Call JS</button>
</div>
@code
private string fromJs;
private ElementReference element;
public async void HandleClick()
fromJs = await JSRuntime.InvokeAsync<string>("setText", element, "Hello from JS call!");
// StateHasChanged();
【问题讨论】:
【参考方案1】:这与 JavaScript 互操作无关。
当您进行此更改时:
//public async void HandleClick()
public async Task HandleClick()
那么这两个部分将同时更新。
几乎总是避免async void
。它是 Timer.Elapsed 等老式事件处理程序的最后手段。 Blazor 事件可以返回 void
或 [async] Task
。
问题是为什么当我再次单击按钮时第 1 部分中的值会发生变化。
ButtonClick 总是会导致重新渲染。但是由于async void
这可能发生在之前 fromJs
被分配。 await JSRuntime.InvokeAsync(...)
中的 await 允许这样做。在下一次单击时,您将看到 fromJs 的先前值出现在第 1 部分中。
使用"Hello from JS call! "+DateTime.Now
来查看这个版本。
【讨论】:
【参考方案2】:Blazor“内部”事件处理程序代码如下所示:
var task = InvokeAsync(EventMethod);
StateHasChanged();
if (!task.IsCompleted)
await task;
StateHasChanged();
如果您将任务传递为 void,如下所示:
public async void HandleClick()
没有什么可以等待的。 task
已完成,最终的渲染事件永远不会发生。这就是为什么任何async
处理程序(即带有等待的方法),如上所述,必须返回一个任务。
所以回答你的问题。第 1 部分中的值已更新,但在重新渲染组件之后 - 没有要等待的任务。当您再次单击该按钮时,您会显示“最后一个”值,即最后一次单击按钮的值,而不是当前单击。如果您将文本设置为点击时间,您会看到这一点。
【讨论】:
是的,正如您在此处显示的,总是有 1 次调用 StateHasChanged()。第二个用于异步处理程序。我在找这件作品。 @HenkHolterman。您会在许多 Blazor 代码库中看到相同的基本模式 - 就像ComponentBase
如何运行 OnInitializedAsync
和 OnParametersSetAsync
。以上是关于何时在 Blazor 组件中调用 StateHasChanged()的主要内容,如果未能解决你的问题,请参考以下文章
在 blazor 中使用自定义组件时在注入的差异服务中调用 HttpContextAccesor 后为 null
如何从 Blazor 组件调用“/Identity/Account/ExternalLogin”?
如何从服务器端 Blazor 应用程序中的 Blazor 组件调用 razor 页面而不导致页面刷新
如何在 Blazor 中引用通过 DynamicComponent 创建的组件?