首页 > 解决方案 > 从 NavigationManager.LocationChanged 内部调用异步方法

问题描述

NavigationManager.LocationChanged用来捕获查询字符串。获取查询字符串值后,我正在进行 ajax 调用,这是异步的。LocationChanged 本身是同步方法,貌似没有异步版本的LocationChanged. 而当从LocationChanged内部调用async方法时,async方法设置的值会滞后一步。

这是复制品:

@page "/investigate"
@implements IDisposable
@inject NavigationManager NM

<h1>Sync: @SyncValue</h1>
<h1>Async: @AsyncValue</h1>
<button @onclick="TriggerLocationChange">Increment</button>

@code {
    private string SyncValue;
    private string AsyncValue;
    private int Counter = 1;

    protected override void OnInitialized()
    {
        NM.LocationChanged += OnLocationChanged;
    }

    public void Dispose()
    {
        NM.LocationChanged -= OnLocationChanged;
    }

    private void OnLocationChanged(object sender, LocationChangedEventArgs args)
    {
        // sync action, just for comparison
        SyncValue = (Counter * 1000).ToString();

        DoSomeAsync();
    }

    private async Task DoSomeAsync()
    {
        // http call to server
        await Task.Delay(1);

        AsyncValue = (Counter * 1000).ToString();
    }

    private void TriggerLocationChange()
    {
        Counter++;
        NM.NavigateTo("investigate?counter=" + Counter);
    }
}

@AsyncValue落后一步@SyncValue

从 LocationChanged 内部调用时,如何防止异步方法滞后?

标签: blazorblazor-client-side

解决方案


经过大量的试验和错误,这是我发现的:

  1. LocationChanged 运行时尚未设置路由参数值。这在我上面的示例中没有显示,但对我来说很重要。路由参数可以从 URL 中手动提取,或者我们可以等到 blazor 使用await Task.Delay(1).

  2. StateHasChanged()在异步方法结束时调用。

  3. 根据文档,我们应该用base.InvokeAsync(() => ...)

经过这些修改后,OnLocationChanged 变为:

private void OnLocationChanged(object sender, LocationChangedEventArgs args)
{
    // ...

    base.InvokeAsync(async () =>
    {
        await Task.Delay(1);  // wait for blazor to populate route parameters
        await DoSomeAsync();
        StateHasChanged();
    });
}

推荐阅读