Blazor WASM 中的意外 UI 绑定行为
Unexpected UI binding behavior in Blazor WASM
我 运行 在 Blazor WASM 和 Blazor 服务器之间的 UI 绑定行为中出现了意想不到的(且无法解释的)差异。给定以下 razor 组件,“发送”按钮在请求期间被正确禁用,在 Blazor 服务器和 Blazor WASM 中:
<MudButton Disabled="isProcessing" OnClick="Submit">Send</MudButton>
@code {
private bool isProcessing;
private async Task Submit()
{
isProcessing = true;
var contacts = await Mediator.Send(getContacts);
isProcessing = false;
}
}
在向提交方法添加第二个等待调用 (IsValidAsync()
) 后,按钮现在 在 Blazor WASM 请求期间保持启用状态,我认为这是错误的.在 Blazor Server 中,它仍然按预期被禁用:
private async Task Submit()
{
if (await validator.IsValidAsync())
{
isProcessing = true;
var contacts = await Mediator.Send(getContacts);
isProcessing = false;
}
}
是否有明确的理由说明为什么这种绑定在 Blazor WASM 中不起作用?或者这是 Blazor 中的明显错误?
我很惊讶它的行为不同,但服务器和 WASM 之间存在显着差异,这可以解释发生了什么。我对 MudBlazor 不是很熟悉,所以我不确定 MudBlazor 的内部结构是如何工作的。
不同之处在于浏览器只有一个线程用于所有操作。服务器实例上有多少服务器就有多少可用,几乎所有情况都不止一个。
尝试:
private async Task Submit()
{
isProcessing = true;
if (await validator.IsValidAsync())
{
var contacts = await Mediator.Send(getContacts);
}
isProcessing = false;
}
或
private async Task Submit()
{
if (await validator.IsValidAsync())
{
isProcessing = true;
await InvokeAsync(StateHasChanged);
var contacts = await Mediator.Send(getContacts);
isProcessing = false;
}
}
事件处理程序基本上是这样做的:
var task = Submit();
StateHasChanged();
if (!task.IsCompleted || !task.IsCanceled)
{
await task;
StateHasChanged();
}
您可以在 ComponentBase
中看到这种模式。它说如果任务产生,那么我们更新 UI,等待它完成,然后再次更新 UI。如果它没有产生,那么我们会在它完成后更新 UI。我的服务器和 WASM 代码的行为相同 - 当然你的不同。
您的代码在 if (await validator.IsValidAsync())
中产生,因此第一个 StateHasChanged
在 isProcessing
设置之前被调用。
规则是您可以免费获得 2 次隐含的 StatehasChanged() 调用,1 次在您的事件处理程序之前,1 次在您的事件处理程序之后。
所以你在第一个 await 中得到一个 'free update' 但是当你的代码中有更多步骤(需要输出)时你需要帮助:
private async Task Submit()
{
if (await validator.IsValidAsync()) // consumes the first StateHasChanged
{
isProcessing = true;
StateHasChanged(); // request an update
var contacts = await Mediator.Send(getContacts); // update UI in background
isProcessing = false;
}
// one implied StateHasChanged for free again
}
这个模式应该用在Server和Wasm上。原始代码在服务器上为您工作的原因尚不清楚。它可能是来自 IsValidAsync() 的侥幸,具有非异步代码路径。
我 运行 在 Blazor WASM 和 Blazor 服务器之间的 UI 绑定行为中出现了意想不到的(且无法解释的)差异。给定以下 razor 组件,“发送”按钮在请求期间被正确禁用,在 Blazor 服务器和 Blazor WASM 中:
<MudButton Disabled="isProcessing" OnClick="Submit">Send</MudButton>
@code {
private bool isProcessing;
private async Task Submit()
{
isProcessing = true;
var contacts = await Mediator.Send(getContacts);
isProcessing = false;
}
}
在向提交方法添加第二个等待调用 (IsValidAsync()
) 后,按钮现在 在 Blazor WASM 请求期间保持启用状态,我认为这是错误的.在 Blazor Server 中,它仍然按预期被禁用:
private async Task Submit()
{
if (await validator.IsValidAsync())
{
isProcessing = true;
var contacts = await Mediator.Send(getContacts);
isProcessing = false;
}
}
是否有明确的理由说明为什么这种绑定在 Blazor WASM 中不起作用?或者这是 Blazor 中的明显错误?
我很惊讶它的行为不同,但服务器和 WASM 之间存在显着差异,这可以解释发生了什么。我对 MudBlazor 不是很熟悉,所以我不确定 MudBlazor 的内部结构是如何工作的。
不同之处在于浏览器只有一个线程用于所有操作。服务器实例上有多少服务器就有多少可用,几乎所有情况都不止一个。
尝试:
private async Task Submit()
{
isProcessing = true;
if (await validator.IsValidAsync())
{
var contacts = await Mediator.Send(getContacts);
}
isProcessing = false;
}
或
private async Task Submit()
{
if (await validator.IsValidAsync())
{
isProcessing = true;
await InvokeAsync(StateHasChanged);
var contacts = await Mediator.Send(getContacts);
isProcessing = false;
}
}
事件处理程序基本上是这样做的:
var task = Submit();
StateHasChanged();
if (!task.IsCompleted || !task.IsCanceled)
{
await task;
StateHasChanged();
}
您可以在 ComponentBase
中看到这种模式。它说如果任务产生,那么我们更新 UI,等待它完成,然后再次更新 UI。如果它没有产生,那么我们会在它完成后更新 UI。我的服务器和 WASM 代码的行为相同 - 当然你的不同。
您的代码在 if (await validator.IsValidAsync())
中产生,因此第一个 StateHasChanged
在 isProcessing
设置之前被调用。
规则是您可以免费获得 2 次隐含的 StatehasChanged() 调用,1 次在您的事件处理程序之前,1 次在您的事件处理程序之后。
所以你在第一个 await 中得到一个 'free update' 但是当你的代码中有更多步骤(需要输出)时你需要帮助:
private async Task Submit()
{
if (await validator.IsValidAsync()) // consumes the first StateHasChanged
{
isProcessing = true;
StateHasChanged(); // request an update
var contacts = await Mediator.Send(getContacts); // update UI in background
isProcessing = false;
}
// one implied StateHasChanged for free again
}
这个模式应该用在Server和Wasm上。原始代码在服务器上为您工作的原因尚不清楚。它可能是来自 IsValidAsync() 的侥幸,具有非异步代码路径。