Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I am seeing OnAfterRenderAsync() get called before OnInitializedAsync() completes

Is this possible? That OnAfterRenderAsync() will be called before OnInitializedAsync() completes?

If so, I then need to have my code in OnAfterRenderAsync(), in this case, be called at the end of OnInitializedAsync() instead. It's a piece of cake to have a method that is called from each and whoever is 2nd executes it.

In this case is a counter inside a lock { ... } the best approach? Or should I take another approach?

In _Host.cshtml I have:

<component type="typeof(HeadOutlet)" render-mode="Server" />

In this mode OnInitializedAsync() is called once.

like image 610
David Thielen Avatar asked Oct 27 '25 00:10

David Thielen


2 Answers

Is this possible?

Yes. It is well documented:

Note
Asynchronous actions performed in lifecycle events might not have completed before a component is rendered.

at the end of OnInitializedAsync() instead.

Why not call it there, and only there, all the time.

is a counter inside a lock { ... } the best approach?

No, I would stay away from lock. The lifecycle is effectively single-threaded so you don't need it. Using a counter or boolean is thread-safe already.

like image 121
Henk Holterman Avatar answered Oct 29 '25 19:10

Henk Holterman


Here's some demo code that documents it does happen and how to detect the OnInitializedAsync completion.

I've added several renders during OnInitializedAsync to show that it's only the last OnAfterRender that runs after OnInitializedAsync. The code uses a special version of ComponentBase that douments each step of the process with Console writes. It's available in the Blazr.BaseComponents package.

Why? As I've already said in previous answers, OnAfterRender is a UI event not directly coupled with the lifecycle methods. The Synchronisation Context prioritizes posted code (by the Renderer) over UI interaction code (UI events). When UI events run is dictated by what's on the SC queue [such as how long real awaits take].

Here's the demo code which shows how to detect the last render using a simple bool:

@page "/"
@inherits Blazr.BaseComponents.ComponentBase.DocumentedComponentBase

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

@code {
    private bool _onInitialized;

    protected override async Task OnInitializedAsync()
    {
        await Task.Delay(250);
        this.StateHasChanged();
        await Task.Delay(250);
        this.StateHasChanged();
        await Task.Delay(250);

        // OnInitialized and and OnInitializedAsync have both now completed
        _onInitialized = true;
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (_onInitialized)
        {
            // runs only once on the last render after OnInitializedSync completes
            _onInitialized = false;
            Console.WriteLine("After Initialized code has run.");
        }
    }
}

And here's the console output to show what's happening:

f1b4 - Home => Component Initialized
f1b4 - Home => Component Attached
f1b4 - Home => SetParametersAsync Started
f1b4 - Home => OnInitialized sequence Started
f1b4 - Home => Awaiting Task completion
f1b4 - Home => StateHasChanged Called
f1b4 - Home => Render Queued
f1b4 - Home => Component Rendered
f1b4 - Home => OnAfterRenderAsync Started
f1b4 - Home => OnAfterRenderAsync Completed
f1b4 - Home => StateHasChanged Called
f1b4 - Home => Render Queued
f1b4 - Home => Component Rendered
f1b4 - Home => OnAfterRenderAsync Started
f1b4 - Home => OnAfterRenderAsync Completed
f1b4 - Home => StateHasChanged Called
f1b4 - Home => Render Queued
f1b4 - Home => Component Rendered
f1b4 - Home => OnAfterRenderAsync Started
f1b4 - Home => OnAfterRenderAsync Completed
f1b4 - Home => OnInitialized sequence Completed
f1b4 - Home => OnParametersSet Sequence Started
f1b4 - Home => StateHasChanged Called
f1b4 - Home => Render Queued
f1b4 - Home => Component Rendered
f1b4 - Home => OnParametersSet Sequence Completed
f1b4 - Home => SetParametersAsync Completed
f1b4 - Home => OnAfterRenderAsync Started
After Initialized code has run.
f1b4 - Home => OnAfterRenderAsync Completed
like image 31
MrC aka Shaun Curtis Avatar answered Oct 29 '25 17:10

MrC aka Shaun Curtis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!