调用 StateHasChanged 与返回任务

Calling StateHasChanged vs returning Task

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

在我的第一次尝试中,我创建了一个方法,该方法会 post 一个新的 WeatherForecast 模型到我的网络 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);
}

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

听说可以打电话

StateHasChanged() 

启动更改以呈现列表的新预测,目前还不错。在阅读了一些关于 StateHasChanged 的​​内容之后,我似乎不应该经常使用它,而且它会显示出不良做法的迹象,所以我尝试了一位同事的建议,他说我需要将 Task 添加为 return 类型而不是而不是像这样对函数无效:

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

    var forecast = await response.Content.ReadFromJsonAsync<WeatherForecast>();
    forecasts.Add(forecast);
}

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

如果我的方法不等待异步操作的结果,有人能解释为什么 StateHasChanged 似乎有效吗?

谢谢

Blazor 在事件处理程序完成时自动调用 StateHasChanged。这是来自 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;
    }

Blazor 等待事件处理程序 return。然后,它调用 StateHasChanged。如果 returned 任务未完成,它将等待任务并再次调用 StateHasChanged

async void 的情况下,returned 任务总是完成的,所以它永远不会等待它并调用第二个 StateHasChanged。在这种情况下,您需要手动调用它。但更好的方法是避免 async void 这几乎总是一件坏事。

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