Search code examples
blazorasyncdata

What is the Blazor 8 equivalent of asyncdata in Vuejs


I'm learning how to use Blazor and I noticed that the weather sample page "flickers" when it's reloaded because the server sends random data to the browser and renders it. Then the client sends random data and renders it too.

In Vuejs, there is a hook called "asyncdata" that ensures that this doesn't happen. It ensures that data is rendered only once by whichever system (server or client) came first. Is there something like that for Blazor?

This is what the sample page looks like:

@page "/weather"

<PageTitle>Weather</PageTitle>

<h1>Weather</h1>

<p>This component demonstrates showing data.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[]? forecasts;

    protected override async Task OnInitializedAsync()
    {
        // Simulate asynchronous loading to demonstrate a loading indicator
        await Task.Delay(500);

        var startDate = DateOnly.FromDateTime(DateTime.Now);
        var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
        forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = startDate.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = summaries[Random.Shared.Next(summaries.Length)]
        }).ToArray();
    }

    private class WeatherForecast
    {
        public DateOnly Date { get; set; }
        public int TemperatureC { get; set; }
        public string? Summary { get; set; }
        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    }
}

I've also attached a link to the video showing the flickering issue: https://imgur.com/a/dk7UwQJ


Solution

  • There is an OnInitializedAsync lifecycle event that you can hook into. Using await for any async calls made from there will ensure the page isn't rendered until after the async call finished.

    For example, you could make an async call to some injected service:

    @if (MyData != null)
    {
      @foreach (var item in MyData)
      {
        <div>@item</div>
      }
    }
    
    @*Inject the service here*@
    @inject IMyService MyService
    
    @code {
      // property to store the data
      private List<string> MyData { get; set; }
    
      // this method is invoked by blazor as part of the 
      // pre-rendering lifecycle
      protected override async Task OnInitializedAsync()
      {  
         // load the data here and wait for it to complete
         MyData = await MyService.GetMyDataAsync();
      }
    }
    

    The docs: Component initialization (OnInitialized{Async})

    Edit

    You may be experiencing the Blazor "double render". There is a relevant section in the docs that I linked above that explains this.

    Blazor apps that prerender their content on the server call OnInitializedAsync twice:

    • Once when the component is initially rendered statically as part of the page.
    • A second time when the browser renders the component.

    To prevent developer code in OnInitializedAsync from running twice when prerendering, see the Stateful reconnection after prerendering section. The content in the section focuses on Blazor Web Apps and stateful SignalR reconnection. To preserve state during the execution of initialization code while prerendering, see Prerender ASP.NET Core Razor components.