Blazor中的StateHasChanged()与InvokeAsync(StateHasChanged) [英] StateHasChanged() vs InvokeAsync(StateHasChanged) in Blazor

查看:200
本文介绍了Blazor中的StateHasChanged()与InvokeAsync(StateHasChanged)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道调用 StateHasChanged()方法会通知组件状态已更改并且应该重新呈现.

I know that calling the StateHasChanged() method notifies the component that the state has changed and that it should re-render.

但是,我还看到在其他人的代码中对 await InvokeAsync(StateHasChanged) await InvokeAsync(()=> StateHasChanged())的调用,但是我不知道不太了解它与 StateHasChanged()的比较方式,何时应该偏爱一个,以及为什么.

However, I also see calls to await InvokeAsync(StateHasChanged) or await InvokeAsync(() => StateHasChanged()) in other people's code, but I don't quite understand how it compares to StateHasChanged() and when should one be favored over the other, and why.

我唯一能找到的信息是 Blazor文档的这一部分,它表示:

The only information I could find was this part of the Blazor docs, it says:

如果必须根据外部事件(例如计时器或其他通知)来更新组件,请使用InvokeAsync方法,该方法将分派到Blazor的同步上下文.

In the event a component must be updated based on an external event, such as a timer or other notifications, use the InvokeAsync method, which dispatches to Blazor's synchronization context.

我不太明白这一点.它只是说"...派发到Blazor的同步上下文",但我对此并不满意!什么是"Blazor的同步上下文"?

I don't quite get this. It just says "...which dispatches to Blazor's synchronization context", but I'm not quite satisfied with that! What is "Blazor's synchronization context"?

我尝试在 Timer Elapsed 中调用 StateHasChanged()-而不是 InvokeAsync(StateHasChanged)-code>事件,它可以按预期运行,没有任何问题.我应该改为调用 await InvokeAsync(StateHasChanged)吗?如果是的话,为什么到底是什么?我觉得这里可能有一些我不知道的重要细微差别.

I have tried calling StateHasChanged() - instead of InvokeAsync(StateHasChanged) - in a Timer's Elapsed event, and it works as expected, without any issues. Should I be calling await InvokeAsync(StateHasChanged) instead?! And if so, why exactly? I feel like there's probably some important nuance here that I'm unaware of.

我也见过像 InvokeAsync(()=> InvokeAsync(Something))这样的调用,为什么呢?

I've also seen calls like InvokeAsync(() => InvokeAsync(Something)), again, why?

另外,我有时还会看到在没有 await 的情况下调用 InvokeAsync()的方法,该怎么办?!

Plus, I also sometimes see InvokeAsync() called without await, what the deal with that?!

推荐答案

我尝试在计时器的Elapsed事件中调用StateHasChanged()而不是InvokeAsync(StateHasChanged),它可以按预期工作

I have tried calling StateHasChanged() - instead of InvokeAsync(StateHasChanged) - in a Timer's Elapsed event, and it works as expected

那一定是在WebAssembly上.当您在Blazor Serverside上尝试该操作时,我会期望出现异常.StateHasChanged()检查它是否在正确的线程上运行.

That must have been on WebAssembly. When you try that on Blazor Serverside I would expect an exception. StateHasChanged() checks if it runs on the right thread.

核心问题是渲染和​​调用StateHasChanged都必须在主(UI)线程上进行.DOM的卷影副本不是线程安全的.

The core issue is that the rendering and calling StateHasChanged both have to happen on the main (UI) thread. The shadow copy of the DOM is not thread-safe.

主要的Blazor生命周期事件(OnInit,AfterRender,ButtonClick)都在该特殊线程上执行,因此在极少数情况下,您需要StateHasChanged()即可在没有InvokeAsync()的情况下调用它.

The main Blazor life-cycle events (OnInit, AfterRender, ButtonClick) are all executed on that special thread so in the rare case that you need StateHasChanged() there it can be called without InvokeAsync().

计时器是不同的,它是外部事件".因此您无法确定它会在正确的线程上执行.InvokeAsync()将工作委托给Blazor的SynchronizationContext,以确保它确实在主线程上运行.

A Timer is different, it is an "external event" so you can't be sure it will execute on the correct thread. InvokeAsync() delegates the work to Blazor's SynchronizationContext that will ensure it does run on the main thread.

但是Blazor WebAssembly只有1个线程,因此暂时外部事件也总是在主线程上运行.这意味着当您错误地执行此Invoke模式时,您将不会注意到任何东西.直到一天,当Blazor Wasm最终获得真实线程时,您的代码才会失败.您的计时器也会进行实验.

But Blazor WebAssembly only has 1 thread so for the time being external events always run on the main thread too. That means that when you do this Invoke pattern wrong you won't notice anything. Until one day, when Blazor Wasm finally gets real threads, your code will fail. As will your Timer experiment.

什么是"Blazor的同步上下文"?

What is "Blazor's synchronization context"?

在.net中,同步上下文确定等待之后(之后)发生的情况.不同的平台具有不同的设置,Blazor synccontext非常类似于WinForms和WPF.主要是默认值是 .ConfigureAwait(true):在同一线程上恢复.

In .net a sync context determines what happens with (after) await. Different platforms have different settings, the Blazor synccontext is a lot like that of WinForms and WPF. Mainly, the default is .ConfigureAwait(true): resume on the same thread.

有时我会在顶级Blazor Wasm代码中看到 .ConfigureAwait(false).当我们在那里找到真正的线程时,也将崩溃.可以在blazor调用的服务中使用它.

I sometimes see .ConfigureAwait(false) in toplevel Blazor Wasm code. That too will blow up when we get real threads there. It is fine to use in services called from blazor.

最后, await InvokeAsync(StateHasChanged) await InvokeAsync(()=> StateHasChanged()与C#中的lambda无关,与Blazor无关.第一种简写形式效率更高.

And finally, await InvokeAsync(StateHasChanged) or await InvokeAsync(() => StateHasChanged() is just about lambda's in C#, nothing to do with Blazor. The first short form is a little more efficient.

有时我还会看到在没有 await

尽管通常会起作用,但这从来不是一个好主意.比将调用方法(如Timer的OnTick)设置为 async void 更好,因此请在同步代码中使用它.

That is never a good idea, although it will usually work. It is better than making the calling method (like the Timer's OnTick) an async void, so use this in synchronous code.

这篇关于Blazor中的StateHasChanged()与InvokeAsync(StateHasChanged)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆