Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should data be loaded asynchronously in Blazor

Tags:

blazor

I have been playing with Blazor and trying to build a simple application. One of the first things I tried to do was to load data asynchronously (in my case from LocalStorage).

protected override async Task OnInitAsync()
{
    await Log.Log($"{nameof(IndexComponent)}.{nameof(OnInitAsync)}");
    Model = await LocalStorage.GetItem<DataModel>("model");
}

My rendering code looked like this:

<div>@Model.Attribute</div>

I was getting a NullReferenceException when rendering the page, plus the browser went into an unresponsive state at which point all I could was to close the browser tab and restart the Blazor application.

Even though it turned out this behaviour is by-design, I haven't found it explained on any piece of documentation and I think it's unexpected enough to grant sharing here. Hopefully it will help someone else (see my own answer below).

like image 836
Rodolfo Grave Avatar asked Nov 20 '18 21:11

Rodolfo Grave


People also ask

Is Blazor async?

We can perform asynchronous calls in a Blazor application using async and await keywords for calling any asynchronous Task or performing any operation.

What is OnInitializedAsync in Blazor?

Component initialization ( OnInitialized{Async} ) 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.


1 Answers

It all boils down to:

Blazor calls your OnInitAsync method and renders your page first time immediately after first suspension (await). Then it renders your page again when your method finishes.

There are two solutions. The first one is to make sure your rendering code handles the case in which Model is null. So, instead of:

<div>@Model.Attribute</div>

use:

<div>@Model?.Attribute</div>

which would generate an empty div, or

@if (Model != null)
{
    <div>@Model.Attribute</div>
}

which does not generate the div at all.

The other, simpler, solution is to make sure Model is never null:

protected DataModel Model { get; } = new DataModel();

Initially I raised an issue in Blazor's GitHub, from where I copied the answer almost verbatim: https://github.com/aspnet/Blazor/issues/1703

Very helpful members of the community very quickly pointed out what the issue was, and all the credit goes to them. I'm just trying to help other people by bringing the knowledge to StackOverflow.

like image 93
Rodolfo Grave Avatar answered Jan 01 '23 10:01

Rodolfo Grave