我正在尝试弄清楚如何在单击按钮后刷新客户端组件。
带有示例的存储库链接: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 :<
}
我试图使用它。状态已更改((;但是没有反应。 作为一种解决方法,我可以强制您再次导航到同一网站,但刷新"整个"网站而不是组件。
关于如何处理它的任何想法?
整个代码(剥离到最低限度(:
@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,这意味着我不必在单击按钮后再次运行相同的代码。希望你明白我的意思。
要获得所需的输出,您只需从以下位置稍微打乱行:
private async void ButtonClick()
{
await (some API Call); // UI checks if an update is needed (No)
result = null; // now an update is needed
this.StateHasChanged(); <--- Doesnt work :< // actually: not needed
}
自:
private async Task ButtonClick()
{
result = null; // change the state
//this.StateHasChanged(); // not needed, a request is pending
await (some API Call); // should show '<h3>Loading</h3>' now
}
请注意,当await
释放线程时,UI 会更新。
但是,从您的回答中,我们得到
var APICall = await Http.GetAsync("SomeAPI");
Thread.Sleep(2000);
当Http.GetAsync("SomeAPI");
确实是一个异步调用而不仅仅是一些备用伪代码时,这应该有效。因为Thread.Sleep(2000);
真的会冻结东西。
如果要确保:
private async Task GetData()
{
await Task.Delay(1); // 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
要好得多,但这不是这里的直接问题。
从这里:
Blazor 使用同步上下文 (同步上下文( 强制实施单个逻辑执行线程。组件的生命周期方法和 Blazor 引发的任何事件回调在同步上下文中执行。
Blazor Server 的同步上下文尝试模拟单线程环境,以便它与浏览器中的 WebAssembly 模型(单线程(紧密匹配。在任何给定的时间点,工作只在一个线程上执行,给人一种单一逻辑线程的印象。没有两个操作同时执行。
因此,作为enetasnwered,您应该使用async Task
签名而不是async void
。
我已经将API调用移动到另一个方法,并且在OnInitializedAsync中我调用了它。
然后,当我重置结果变量以查看加载状态时,我可以"刷新"组件以实现您需要添加的内容。状态已更改((
现在我有一个响应组件来响应正在发生的更新:)
@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();
}
}