Phuc Vuong
Phuc Vuong

Reputation: 223

Blazor Components: Data disappears and loads agains after 4 seconds

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

Answers (2)

Henk Holterman
Henk Holterman

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

enet
enet

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:

  1. The OnInitializedAsync method starts executing

  2. Encountering an awaited method call (await Task.Delay(4000);), the result of which is yielding control to the calling code.

  3. Blazor starts rendering or outputting the UI. First rendering the Html markup <p>Hello world</p>

  4. 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.

  5. 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

Related Questions