在Blazor中,为什么调用NavigationManager.NavigateTo有时会导致使用旧值进行额外的OnParametersSetAsync调用?

在Blazor中,为什么调用NavigationManager.NavigateTo有时会导致使用旧值进行额外的OnParametersSetAsync调用?,blazor,blazor-webassembly,Blazor,Blazor Webassembly,在Blazor中,为什么调用NavigationManager.NavigateTo(string)有时会导致使用旧值额外调用OnParametersSetAsync调用 我有一个页面,它通过回调事件对单击做出反应,父级调用NavigationManager.NavigateTo来设置新的URL,这会导致父级的参数更新,然后组件通过OnParametersSetAsync响应新值但在此之前,还使用旧值调用了OnParametersSetAsync——显然是在它们更改之前。似乎我的第二次调用通常在

在Blazor中,为什么调用
NavigationManager.NavigateTo(string)
有时会导致使用旧值额外调用OnParametersSetAsync调用

我有一个页面,它通过回调事件对单击做出反应,父级调用
NavigationManager.NavigateTo
来设置新的URL,这会导致父级的参数更新,然后组件通过OnParametersSetAsync响应新值但在此之前,还使用旧值调用了OnParametersSetAsync——显然是在它们更改之前。似乎我的第二次调用通常在第一次(错误的)调用之前完成,因此第一次调用在最后完成,结果很糟糕

那么,对
OnParametersSetAsync
的第一个看似虚假且不正确的调用是否只是因为在事件处理程序等待时某个属性发生了更改而发生的呢?我如何确定这是一个虚假的电话

下面是一个触发它的示例:

@page "/demo"
@page "/demo/{SelectedOrderId:int}"

@using Microsoft.Extensions.Configuration

@inject IHttpClientFactory clientFactory
@inject IToastService toastService
@inject IConfiguration Configuration
@inject NavigationManager navigationManager

  <div class="mt-4 container-fluid">
    <div class="row">
      <div class="col-12 col-md-8 order-md-2">
        Order @OrderDetail?.OrderId @OrderDetail?.ProductCode
      </div>
      <div class="col-12 col-md-4 order-md-1">
        @foreach (var order in Orders)
        {
          <button @onclick="async () => await OnSelectedOrderIdChanged(order.OrderId)">@order.OrderId</button>        }
      </div>
    </div>

  </div>

@code {
    [CascadingParameter]
    public AppState State { get; set; } = null!;

    public int? CustomerId { get; set; } = 8010;

   [Parameter]
    public int? SelectedOrderId { get; set; } = null;

    private List<Order> Orders { get; set; } = new List<Order>();
    private OrderDetail? OrderDetail { get; set; } = null;


    protected override async Task OnInitializedAsync()
    {
      await LoadOrdersList();
    }

    protected override async Task OnParametersSetAsync()
    {
      Console.WriteLine($"params changed to order {SelectedOrderId}");
      await LoadOrderDetail();
      Console.WriteLine($"done loading order {SelectedOrderId}");

    }

    private async Task LoadOrdersList()
    {
      string serviceEndpoint = Configuration["MyServiceUrl"];
      string url = $"{serviceEndpoint}/orders?customerId={CustomerId}";
      Orders = await clientFactory.CreateClient().GetFromJsonAsync<List<Order>>(url);
    }

    private async Task LoadOrderDetail()
    {
      string serviceEndpoint = Configuration["MyServiceUrl"];
      string url = $"{serviceEndpoint}/orders/{SelectedOrderId}";
      OrderDetail = await clientFactory.CreateClient().GetFromJsonAsync<OrderDetail>(url);
    }


    private async Task OnSelectedOrderIdChanged(int? newOrderId)
    {
      SelectedOrderId = newOrderId;
      await Task.Yield();  // could be anything
      navigationManager.NavigateTo($"/demo/{newOrderId}");
    }
}
页面中的显示显示订单48026500!据推测,应该导致的UI更新很早就发生了。那么,我如何确定48026500的调用是假的(或者它不代表对参数的真正更改)


我尝试跟踪上一个值并将其与当前值进行比较,但这没有帮助,因为“新”值是在旧值之前处理的,也就是说,
LoadOrderDetail()
上面运行了两次,它们相互竞争,并且通常先运行新值的LoadOrderDetail,然后使用旧值LoadOrderDetail完成并覆盖新数据。那么如何避免对这些虚假事件调用LoadOrderDetail呢?

NavigationManager.NavigateTo(string)
只调用一次。这是你的问题(你很接近了!):

[参数]
公共整数?SelectedOrderId{get;set;}=null;
. . . . .
SelectedOrderId上的专用异步任务已更改(int?newOrderId)
{
//设置[Parameter]道具可能会“起作用”,但不是有意的
SelectedOrderId=newOrderId;
等待任务;
//这也将更新SelectedOrderId
navigationManager.NavigateTo($“/demo/{newOrderId}”);
}
请注意,
[参数]
属性应由家长或通过
@page
路由参数设置,而不是由组件本身设置

navigationManager.NavigateTo($“/demo/{newOrderId}”)将设置
选择的顺序
;这是更新页面
[参数]
属性的正确方法
因此,
SelectedOrderId=newOrderId
不是必需的。删除该行,您的代码将按预期工作


此外,您还提到跟踪以前的值以确定何时更新。这可能很有用(尤其是与搭配使用时)。最简单的方法是跟踪上一个id而不是上一个值。应用于您的代码:

[参数]
公共整数?SelectedOrderId{get;set;}
私人整数?PreviousOrderId{get;set;}
. . . . .
受保护的重写异步任务OnParametersSetAsync()
{
WriteLine($”参数更改为顺序{SelectedOrderId}”);
if(PreviousOrderId!=SelectedOrderId){
//如果id不变,则防止加载发生。
等待LoadOrderDetail();
}
PreviousOrderId=SelectedOrderId;
WriteLine($“完成加载顺序{SelectedOrderId}”);
}

这可能与此相关,但并没有回答问题:这里讨论的是更强大的功能。您跟踪了更新的哪个价值?你在哪里试过比较?另外,为什么要设置参数
SelectedOrderId
的值?是的,查找并消除从路由设置的参数的任何分配似乎是一个非常好的主意。NavigateTo是一种设置它们的方法,我们只需记住NavigateTo只是更改浏览器中的URL,实际上并不重新加载页面或重新初始化组件。NavigateTo之后的下一行代码仍在运行。
params changed to order 48026500

params changed to order 48026528

done loading order 48026528