-
Notifications
You must be signed in to change notification settings - Fork 461
Description
InvokeAsync(StateHasChanged); is a Blazor anti-pattern.
Blazor ensures that only a single thread is working with a component's state at any given time. If you alter your component through something like a Timer then it bypassess that safety process and calls the code directly in a thread that might access your component state at the same time as another.
To help you to avoid having multiple threads using your component's state at the same time, Blazor will throw an exception when StateHasChanged is called from outside of a managed thread. This is to warn you that you are doing "Blazor things" in a thread that wasn't given to you by Blazor.
If you do InvokeAsync(StateHasChanged) then you are still updating your component's state from a thread that Blazor doesn't manage, but hiding the exception that should be raising a red flag to warn you that you likely have thread race-conditions in your code.
Instead, code that is executed from something like a Threading.Timer, Tasks.Timer, or a notification from a SignalR connection you have created yourself, then it should be written like this...
async Task TimerTicked()
{
await InvokeAsync(DoSomething);
}
Where DoSomething includes ALL of the code that interacts with your Blazor component. This ensures that only ONE thread is ever accessing your component's state at any one given moment.
Note that all user interaction, and invokes from JS into Blazor components are already automatically invoked in this way.
You only need to do it for code Blazor doesn't trigger.