Reputation: 223
This is a menu component which is placed in MainLayout. H5 tags show up and disappear in a blink of an eye and then after 4 secs. It loads again. Anyone meet the same problem?
<ul class="nav-title">
<li class="brands">
<div class="menu-dropdown sb-2">
@foreach (var brand in Brands)
{
<div class="nav-column">
<h5>@brand.Header</h5>
<ul>
@foreach (var item in brand.Items)
{
<li>@item.Id</li>
}
</ul>
</div>
}
</div>
</li>
</ul>
@code {
private List<BrandModel> Brands { get; set; } = new List<BrandModel>();
private List<CategoryModel> Categories { get; set; } = new List<CategoryModel>();
private List<ColorModel> Colors { get; set; } = new List<ColorModel>();
protected override async Task OnInitializedAsync()
{
Brands = await HeaderNavComponentService.GetBrandAsync();
Categories = await HeaderNavComponentService.GetCategoryAsync();
Colors = await HeaderNavComponentService.GetColorAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JS.InvokeVoidAsync("lazyLoadNav");
}
}
}
Update to @enet's answer:
render-mode="Server" cuts the blink out and the delay is left.
I actually want to load the data as fast as posible. The prerender speed is exactly what i want it to be. In that blink, it also has the value retrieved from service. I just dont like the part it disappears and loads back after a time which no line of code tells the app to make such behavior.
The way this issue occurs, i predict any dynamic components will have a minimum dead time of (2 seconds + data load time ) due to no data.
It's really sad UX though having to wait for a time to be able to look at the navigation list. It seems my plan to use Blazor for new project is broken :(
Update to Henk's answer:
Really not make sense to me that put StateHasChange() after each assigned variable could help but it did. But still theres flickering.
Then i change render-mode="Server" and the result is expected behavior that no more flickering, the data binds to UI fast.
SO i think whatever u do, OnInitialize will run twice, just it wont bind to UI in pre-render phase if render-mode is put to Server.
Upvotes: 3
Views: 2770
Reputation: 273264
You need to help sometimes:
protected override async Task OnInitializedAsync()
{
Brands = await HeaderNavComponentService.GetBrandAsync();
StateHasChanged();
Categories = await HeaderNavComponentService.GetCategoryAsync();
StateHasChanged();
Colors = await HeaderNavComponentService.GetColorAsync();
}
and those Get___Async() methods need to be really async.
Upvotes: 1
Reputation: 45626
This is a strange behavior and may be a bug. I've succeeded to reproduce it with the simple code below:
@page "/"
<p>Hello world</p>
@if (strings != null)
{
@foreach (var str in strings)
{
<p>@str</p>
}
}
@code{
public List<string> strings { get; set; } = null;
protected override async Task OnInitializedAsync()
{
await Task.Delay(4000);
strings = new List<string>() { "Apple", "Orange", "Banana" };
}
}
As far as I understand the code should work like this:
The OnInitializedAsync method starts executing
Encountering an awaited method call (await Task.Delay(4000);
), the result of which is yielding control to the calling code.
Blazor starts rendering or outputting the UI. First rendering the Html markup <p>Hello world</p>
And then taking a break because of @if (strings != null)
, but Blazor shamelessly ignores my command, enters the loop, and starts rendering the p tags with values that are not yet retrieved... mind you, they should be retrieved only after 4 seconds.
Immediately after the rendering of the p tags with the values from the strings array, Blazor re-render once again, this time only <p>Hello world</p>
, await 4 seconds and then re-render once more, this time <p>Hello world</p>
plus the p tags with the values from the strings array
Very strange indeed... oh wait...I understood the problem... This behavior is the result of setting the render-mode attribute of the component Tag Helper to "ServerPrerendered". Do this and this behavior disappears.
<app>
<component type="typeof(App)" render-mode="Server" />
</app>
Hope this helps...
Upvotes: 2