I recently asked a question regarding the difference between await Task.Run(StateHasChanged);
and await InvokeAsync(StateHasChanged);
in Blazor wasm here.
The conclusion was that await Task.Run(StateHasChanged);
was incorrect and should be avoided; using it would produce the same results as await InvokeAsync(StateHasChanged);
however would fall over when threads are available (The accepted answer explains in detail).
I've updated my codebase to use await InvokeAsync(StateHasChanged);
, however I've discovered there is actually a difference in outcome between the two.
Here's a minimal reproduction of the issue in my application:
Parent
<h1>Parent: @title</h1>
<button class="btn btn-primary" @onclick="() => SetBool(true)">True</button>
<button class="btn btn-primary" @onclick="() => SetBool(false)">False</button>
<Child Bool="@Bool" @ref="Child"></Child>
@code {
private bool Bool = false;
private Child Child;
private string title;
private async void SetBool(bool name)
{
Bool = name;
title = Bool ? "True" : "False";
// NOTE: This will work as expected; Child will be updated with the Parent
// await Task.Run(StateHasChanged);
// NOTE: This will only update the Child the second time it is clicked
await InvokeAsync(StateHasChanged);
await Child.Trigger();
}
}
Child
<h3>Child: @title</h3>
@code {
[Parameter]
public bool Bool { set; get; } = false;
private string title;
public async Task Trigger()
{
title = Bool ? "True" : "False";
await InvokeAsync(StateHasChanged);
}
}
Clicking either the True
or False
button in the parent should update the Bool
value in both the parent and child. Note that the title
variable is only used for a visual display of the Bool
value.
Using await Task.Run(StateHasChanged);
will cause both the parent and child's state to be updated at the same time. On the other hand await InvokeAsync(StateHasChanged);
will update the parent, but not the child; it takes two clicks of the a button to get the respective value in the child component.
Is there an issue with how I'm passing this value to the child component?
Note that using await Task.Run(StateHasChanged);
isn't an option; doing so means I can't test the component with bUnit.
The reproduction code is available here.