Blazor客户端刷新组件

时间:2020-06-26 21:06:43

标签: async-await blazor blazor-client-side blazor-webassembly

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

回购链接,例如: https://github.com/ovie91/RefreshComponent

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

所以我有从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会再次被触发,这意味着单击按钮后不必再次运行相同的代码。希望你明白我的意思。

3 个答案:

答案 0 :(得分: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 Task代替async void更好,但这不是这里的直接问题。

答案 1 :(得分:1)

来自here

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

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

因此,作为 enet asnwered,您应该使用let key = 'your key'; // I suppose you generate the key programatically this.sample[key] = [{first: "", second: ""}]; 签名而不是async Task

答案 2 :(得分:-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(); 

    }

}