0

我试图弄清楚单击按钮后如何刷新客户端组件。

带有示例的回购链接:https ://github.com/ovie91/RefreshComponent

站点 /test 或从导航菜单测试

所以我有从 API 检索数据的 OnInitializedAsync 方法

protected override async Task OnInitializedAsync()
{
     result = await (some API Call);
}

然后我有一个连接到按钮的方法

private async void ButtonClick()
{
     await (some API Call);
     result = null;
     this.StateHasChanged(); <--- Doesnt work :<
}

我曾尝试使用this.StateHasChanged(); 但没有反应。作为一种解决方法,我可以强制您再次导航到同一个网站,但是这个刷新“整个”网站而不是一个组件。

关于如何处理它的任何想法?

整个代码(剥离到最低限度):

@page "/test"
@inject HttpClient Http

@if (result == null)
    {
     <p>Loading...<p>
    }
    else
    {
    @result
     <button @onclick="(() => ButtonClick())">Click</button>
    }

@code {

  private APIObject result;

  protected override async Task OnInitializedAsync()
  {
     result = await (some API Call);
  }
  private async void ButtonClick()
  {
     await (some API Call);
     result = null;
     this.StateHasChanged(); <--- Doesnt work :<
  }
}

更新 我想刷新组件,因此 OnInitializedAsync 将再次被触发,这意味着我不必在单击按钮后再次运行相同的代码。希望你明白我的意思。

4

3 回答 3

2

要获得所需的输出,您只需将行稍微改组,来自:

  private async void ButtonClick()
  {
     await (some API Call);
     result = null;
     this.StateHasChanged(); <--- Doesnt work :<
  }

至:

  private async void ButtonClick()
  {
     result = null;
     this.StateHasChanged();  // should show '<h3>Loading</h3>' now
     await (some API Call);       
  }

但是,从您的回答中我们得到

    var APICall = await Http.GetAsync("SomeAPI");
    Thread.Sleep(2000);

Http.GetAsync("SomeAPI");当真的是异步调用而不仅仅是一些替代伪代码时,这应该可以工作。因为Thread.Sleep(2000);真的会冻死东西。

如果您想确定:

private async Task GetData()
{
    await Task.Yield();    // release the thread for rendering
    var APICall = await Http.GetAsync("SomeAPI");
    Random rnd = new Random();
    Thread.Sleep(2000);  // Task.Delay() is much preferred
    result = "Random Number: " + rnd.Next();
}

Thread.Sleep()适合模拟一些 CPU(不是 I/O)密集型代码。所以我并不是说这是错误的,但要注意其中的区别。

制作事件处理程序要好得多async Taskasync void但这不是这里的直接问题。

于 2020-06-27T23:34:46.083 回答
1

这里

Blazor 使用同步上下文 (SynchronizationContext) 来强制执行单个逻辑线程。组件的生命周期方法和 Blazor 引发的任何事件回调都在同步上下文中执行。

Blazor Server 的同步上下文尝试模拟单线程环境,以便它与浏览器中的 WebAssembly 模型紧密匹配,该模型是单线程的。在任何给定的时间点,工作都只在一个线程上执行,给人一种单一逻辑线程的印象。没有两个操作同时执行。

因此,如enet asnwered,您应该使用async Task签名而不是async void.

于 2020-06-26T21:46:59.433 回答
-1

我已将 API 调用移至另一个方法,并在 OnInitializedAsync 内部调用了它。

然后,当我重置结果变量以查看加载状态时,我可以“刷新”组件以实现您需要添加的内容。this.StateHasChanged()

现在我有一个对正在发生的更新的响应组件:)

@page "/test"
@using System.Threading;
@inject HttpClient Http

@if (result == null)
        {
            <h3>Loading</h3>
        }
        else
        {
        @result
        <button @onclick="(() => ButtonClick())">Click</button>
        }




@code {

    private string result;

    protected override async Task OnInitializedAsync()
    {
        await GetData();

    }
    private async Task GetData()
    {
        var APICall = await Http.GetAsync("SomeAPI");
        Random rnd = new Random();
        Thread.Sleep(2000);
        result = "Random Number: " + rnd.Next();
    }
    private async Task ButtonClick()
    {

        await Http.GetAsync("SomeAPIcall");
        result = null; // required to see loading state.
        this.StateHasChanged(); // when added model is refreshed and Loading state is visible.
        await GetData(); 

    }

}
于 2020-06-27T12:45:47.653 回答