Blazor StateHasChanged 无法正常工作
Posted
技术标签:
【中文标题】Blazor StateHasChanged 无法正常工作【英文标题】:Blazor StateHasChanged does not work correctly 【发布时间】:2021-09-03 00:30:26 【问题描述】:@if (_loading)
....
else
....
....
@code
private bool _loading
...
private void Search()
_loading = false;
StateHasChanged();
Mails.Clear();
Licenses.Clear();
Callings.Clear();
Supports.Clear();
Leads.Clear();
search();
_loading = true;
StateHasChanged();
DOM 在运行时不会改变。仅当您将 _loading 的值更改两次,但仅更改一次时,它才有效。但是,我绝对需要这样做两次。所以我做了一个进度条。如何解决?
【问题讨论】:
@viveknuna 这是一个糟糕的建议。 @viveknuna 因为它阻塞了线程。是的,有better options。 您不需要等待 1000 毫秒,但您确实需要await
为您想要的每次重新渲染提供一些东西 - 通常只需要 await Task.Delay(1)
或 await Task.Yield()
- 产生线程并允许渲染器处理来自 StateHasChanged() 的请求
您使用的是哪个进度条组件或脚本? search
是做什么的?为什么不是异步的?任何可能阻塞的 Blazor 调用都是异步的,例如调用远程服务。这意味着search()
很可能故意阻止了异步操作
@viveknuna 这是一个糟糕的建议,平方。一开始就很可怕。虽然浏览器标签是单线程的,所以Thread.Sleep
将冻结整个标签,绝对没有任何好处。
【参考方案1】:
由于您引用的代码未显示谁调用了搜索,因此这是一个有效的版本,它在组件加载事件和通过按钮单击驱动时使用 Search
。
注意它是异步的并且使用Tasks
。 await Task.Delay(3000);
模拟您的代码。
@page "/Demo"
<h3>Demoblock</h3>
@if (_loading)
<div class="bg-warning p-2 m-2">Loading...</div>
else
<div class="bg-success p-2 m-2">Loaded</div>
<div class="p-2 m-2">
<button class="btn btn-dark" @onclick="DoSearch">New Search</button>
</div>
@code
private bool _loading;
private async Task Search()
_loading = true;
// not needed
//StateHasChanged();
//Mails.Clear();
//Licenses.Clear();
//Callings.Clear();
//Supports.Clear();
//Leads.Clear();
//search();
//Emulate doing the above work
await Task.Delay(3000);
_loading = false;
// not needed
// StateHasChanged();
protected async override Task OnInitializedAsync()
await Search();
private async Task DoSearch(MouseEventArgs e)
await Search();
在伪代码中发生了什么:
Set up a Task when you run the Event - such as OninitializedAsync, On ParametersSetAsync, Mouse/Keyboard Event
If Task has not completed
Render the Component.
Now Wait for the Task to Complete
Render the Component
这里的关键是,只有当你的事件返回一个任务并产生时才会发生第一次渲染。
-
如果您的事件产生但返回 void,则处理程序没有任务等待,因此在事件完成之前运行最后一个渲染。
如果您的代码是同步的,即没有屈服,它会完成,因此任务已完成并且只发生第二次渲染。
【讨论】:
你的伪代码有点模糊。但是,您的代码是正确的,这就是编码的方式。 .Clear() 方法是同步的,Task.Delay() 无法模拟。【参考方案2】:StateHasChanged() 不执行或强制渲染,它只请求一个。 只有在等待或事件处理完成时,主线程被释放一段时间后,才能兑现该请求。
当您没有任何异步工作时,您可以使用 Task.Delay(1) 模拟它。但是你必须 await
所以你的方法必须返回 Task 并且必须自己等待。
private async Task Search() // call it from an Async method
_loading = false;
//StateHasChanged(); // not needed
await Task.Delay(1); // here the UI gets updated
Mails.Clear();
Licenses.Clear();
Callings.Clear();
Supports.Clear();
Leads.Clear();
search(); // tricky naming
_loading = true;
//StateHasChanged(); // not needed
【讨论】:
同意你的观点,但是如果你看不到,很难知道每种方法的作用——我在回答时尽量不要做太多假设。我的方法是异步的,如果唯一的方法是添加一个等待 Task.Delay,那么就可以了。我添加了 3 秒,以便您可以看到它正在工作。我通常使用 Task.Yield,但使用它时有很多城市神话和巫术。 你可以看到他们没有等待。有些事情必须做,否则 UI 不会让步。 你可以假设,但你不能确定。search();
上可能有异步警告。我已经学会了艰难的方式!是的,需要为 UI 更新做出一些贡献!
@MrCakaShaunCurtis 如果search()
上有异步警告,仍然没有等待,即仍然同步调用,即执行仍然无法返回渲染器以便它可以渲染.所以search()
是否被声明为async
并不重要,重要的是它没有被等待。以上是关于Blazor StateHasChanged 无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章
何时在 Blazor 组件中调用 StateHasChanged()
Blazor 组件在 StateHasChanged() 之后未更新
我应该何时调用 StateHasChanged 以及 Blazor 何时自动拦截某些更改?