调用 StateHasChanged 与返回 Task

Peo*_*mer 1 .net c# async-await blazor-webassembly

我正在使用 Blazor Web 程序集项目的基本模板。我试图了解两种不同的方法似乎达到了相同的结果。

在我的第一次尝试中,我创建了一个方法,将新的 WeatherForecast 模型发布到我的 Web api 端点,然后从响应中将新创建的 WeatherForecast 添加到列表中。这是第一种方法:

private async void ValidSubmitHandler()
{
    var response = await Http.PostAsJsonAsync<WeatherForecast>(Configuration["APIBaseUrl"] + "/WeatherForecast", newForecast);

    var forecast = await response.Content.ReadFromJsonAsync<WeatherForecast>();
    forecasts.Add(forecast);
}
Run Code Online (Sandbox Code Playgroud)

我期望 UI 能够使用新添加的预测进行更新,但尽管预测列表添加了新对象,但页面并未更新。我设置了一个断点,并观察到新的预测确实已添加到列表中,但只是 UI 没有呈现对列表状态的更改。

我听说你可以打电话

StateHasChanged() 
Run Code Online (Sandbox Code Playgroud)

启动更改以呈现列表的新预测,目前还不错。在阅读了一些有关 StateHasChanged 的​​内容后,我似乎不应该经常使用它,而且它会显示出不良做法的迹象,因此我尝试了一位同事的建议,他说我需要将 Task 添加为返回类型而不是 void 到函数如下:

private async Task ValidSubmitHandler()
{
    var response = await Http.PostAsJsonAsync<WeatherForecast>(Configuration["APIBaseUrl"] + "/WeatherForecast", newForecast);

    var forecast = await response.Content.ReadFromJsonAsync<WeatherForecast>();
    forecasts.Add(forecast);
}
Run Code Online (Sandbox Code Playgroud)

这确实允许 UI 接收更新,我只能假设 ValidSubmitHandler() 在新预测添加到列表之前退出。

如果我的方法没有等待异步操作的结果,有谁能解释为什么 StateHasChanged 似乎可以工作?

谢谢

mez*_*tou 6

StateHasChanged当事件处理程序完成时,Blazor 会自动调用。以下是来自 GitHub 的相关代码:

    // https://github.com/dotnet/aspnetcore/blob/547de595414d6ebb9ddeaa4a231815449c9f3c60/src/Components/Components/src/ComponentBase.cs#L301
    Task IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, object? arg)
    {
        var task = callback.InvokeAsync(arg);
        var shouldAwaitTask = task.Status != TaskStatus.RanToCompletion &&
            task.Status != TaskStatus.Canceled;

        // After each event, we synchronously re-render (unless !ShouldRender())
        // This just saves the developer the trouble of putting "StateHasChanged();"
        // at the end of every event callback.
        StateHasChanged();

        return shouldAwaitTask ?
            CallStateHasChangedOnAsyncCompletion(task) :
            Task.CompletedTask;
    }
Run Code Online (Sandbox Code Playgroud)

Blazor 等待事件处理程序返回。然后,它调用StateHasChanged. 如果返回的Task未完成,则等待任务并StateHasChanged再次调用。

在 的情况下async void,返回的任务始终已完成,因此它永远不会等待它并调用第二个StateHasChanged。在这种情况下,您需要手动调用它。但更好的方法是避免async void这几乎总是坏事。

我还写了一篇关于组件生命周期ASP.NET Core Blazor 组件生命周期的更深入的博客文章