Blazor is an experimental web framework that is quickly evolving. Therefore, it is possible that some of the content on this blog post is already outdated.

Introduction

Component instances have a lifecycle as Blazor creates, updates, and disposes of them. We can tap into key moments of the lifecycle via a series of methods, also known as lifecycle hooks. We can access them because Blazor components are derived from the Microsoft.AspNetCore.Components.ComponentBase class. This class contains all the lifecycle methods that you can override easily for each component.

Lifecycle Sequence and Timing

Here you can see all the available lifecycle methods in the sequence they get called by Blazor.

MethodTiming
SetParametersAsync()The first method invoked in the lifecycle before any parameter value is assigned to their respective properties. Also called each time new or updated parameters are received.
OnInit()Invoked once, after every parameter value is received and assigned to their respective properties.
OnInitAsync()Invoked once, after OnInit is finished. Any asynchronous operations, that require the component to re-render, should be placed here.
OnParametersSet()Invoked after SetParametersAsync and OnInit are finished and then each time new or updated parameters are received.
OnParametersSetAsync()Invoked after OnParametersSet is finished. Its also invoked each time new or updated parameters are received.
OnAfterRender()Invoked after each render of the component. Called for the first time when the component is initialized and then after every re-render.
OnAfterRenderAsync()Invoked after OnAfterRender is finished. Called for the first time when the component is initialized and then after every re-render.
ShouldRender()Invoked right before a component re-render is executed. Used to suppress current and future renders of the component.

NOTE

Lifecycle methods are always invoked at least once for every component. Even for components that don’t have parameters.

They Aren’t Shared… Wait, what?

Lifecycle methods are not shared between components. Meaning, you have a separate set of lifecycle methods for each component that won’t collide with other components. This gives you greater control over each of them throughout their lifetime. Pretty cool, right?

Lifecycle Methods In Action

Now that you know their sequence and timing, let’s learn a few more things about each method along with some examples to get an even better understanding.

SetParametersAsync()

This is the first method called in a component’s lifecycle. At this point, parameters are yet to be initialized. You can tap into each parameter, if any, and modify them before the component is rendered. Great for parameter validation!

In the following example, you’ll see the SetParametersAsync method in action. To keep things simple, we only log the parameters received to the browser console.

Example

The parent component is sending three parameters to the <ParameterList> component: FirstName, LastName, and Age. They were also bound to separate input fields to update their value and have the SetParametersAsync method trigger again on the child component.

Parent Component
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@page "/parameter-list-parent"

<h2>Parent Component</h2>

<label for="firstName">First name: </label>
<input type="text" name="firstName" bind="firstName" />
<br />
<label for="lastName">Last name: </label>
<input type="text" name="lastName" bind="lastName" />
<br />
<label for="age">Age: </label>
<input type="number" name="age" bind="age" />
<br />
<ParameterList FirstName="@firstName" LastName="@lastName" Age="@age"></ParameterList>

@functions {
    string firstName = "Ryan";
    string lastName = "Reynolds";
    int age = 42;
}

In the child component, we are iterating over the ParameterCollection object whenever a parameter gets a new or updated value from the parent component.

Child Component
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<h2>Child Component</h2>

<p><b>First name:</b> @FirstName</p>
<p><b>Last name:</b> @LastName</p>
<p><b>Age:</b> @Age</p>

@functions {
    [Parameter] string FirstName { get; set; }
    [Parameter] string LastName { get; set; }
    [Parameter] int Age { get; set; }

    public override Task SetParametersAsync(ParameterCollection parameters)
    {
        foreach(var param in parameters)
        {
            Console.WriteLine($"Parameter: {param.Name}, Value: {param.Value.ToString()}");
        }
        return base.SetParametersAsync(parameters);
    }
}

Output

OnInit() and OnInitAsync()

These methods are called when the component is ready to start. At this point, initial parameter values are already available in their respective properties. Use OnInitAsync and the await keyword for any asynchronous operations.

NOTE

OnInitAsync triggers a component refresh when it is done executing.

Let’s now look at an example where both methods are used to modify the value of a parameter.

Example

We are using the OnInit method to initialize the Title parameter if no value is passed from a parent component. Then we change its value again with OnInitAsync after three seconds. This way you’ll see that the component gets re-rendered when OnInitAsync has finished executing. We also added a button to change the Title value to show that the app is functional while the OnInitAsync method is running.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@page "/title-change"

<h1>@Title</h1>

<p>Button click count: @count</p>

<button class="btn btn-primary" onclick="@ButtonClicked">Click me</button>

@functions {
    [Parameter] string Title { get; set; } = string.Empty;

    int count = 0;

    void ButtonClicked()
    {
        Title = "Button was clicked!";
        count++;
    }

    protected override void OnInit()
    {
        if (string.IsNullOrEmpty(Title))
            Title = "Title parameter is empty";
    }

    protected override async Task OnInitAsync()
    {
        await Task.Delay(3000);
        Title = "Updated by OnInitAsync";
    }
}

Output

OnParametersSet() and OnParametersSetAsync()

By the time these methods are called, all parameters have been assigned to their respective properties. They both get executed for the first time on component initialization, right after OnInit, and then each time parameter values are updated by the parent component.

NOTE

OnParametersSetAsync triggers a component refresh when it is done executing.
Example

In the following example, the parent component is sending a random number to the child component when the Generate number button is clicked. This, in turn, triggers a call to the OnParametersSet and OnParametersSetAsync methods on the child component.

Parent Component
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@page "/random-number-parent"

<RandomNumber RandNum="randomNumber"></RandomNumber>
<br />
<button class="btn btn-primary" onclick="@GenerateRandomNumber">Generate number</button>

@functions {
    int randomNumber = 0;
    Random numberGenerator = new Random();

    void GenerateRandomNumber()
    {
        randomNumber = numberGenerator.Next(100);
    }
}

In the child component, we have a table displaying three things: the number of times the OnParametersSet has been called, the random number received by the parent component, and the same random number getting updated by the OnParametersSetAsync after one second.

Child Component
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<style>
    table {display: table;border-collapse: collapse;width: 100%;border-spacing: 2px;}
    table, td, th {border: 1px solid #ddd;text-align: center;}
</style>

<table>
    <tr>
        <th>OnParameterSet calls</th>
        <th>Random number</th>
        <th>Random number with delay</th>
    </tr>
    <tr>
        <td>@count</td>
        <td>@RandNum</td>
        <td>@randNumWithDelay</td>
    </tr>
</table>

@functions {
    [Parameter] int RandNum { get; set; } = 0;
    int randNumWithDelay = 0;
    int count = 0;

    protected override void OnParametersSet()
    {
        count++;
    }

    protected override async Task OnParametersSetAsync()
    {
        await Task.Delay(1000);
        randNumWithDelay = RandNum;
    }
}

In the output, you’ll notice that the OnParametersSet method is called once when the component is initialized and then each time the RandNum parameter receives a new value.

Output

OnAfterRender() and OnAfterRenderAsync()

These methods are essential when you need to perform additional initialization steps using the rendered content, such as initializing JavaScript libraries.

NOTE

Never call the StateHasChanged method inside of OnAfterRender or OnAfterRenderAsync unless you have a good reason because it can cause an endless loop.

In the following example, we initialize a small JavaScript library by using the OnAfterRenderAsync method. We also use what’s called JavaScript interop which lets us call JavaScript functions from our .NET code. Cool, right?

Example

In this component, we use the OnAfterRenderAsync method to initialize a small JavaScript library named Micromodal.js which requires its modals to be initialized when we want to use them. We also override the OnAfterRender method to write a message to the console every time it gets invoked.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@page "/micro-modal"
@inject IJSRuntime JSRuntime;

<h2>Micro Modal</h2>

<h4>Let's see our micromodal in action!</h4>

<button class="btn btn-secondary btn-lg" data-micromodal-trigger="modal-1">Open modal</button>

@functions {
    int count = 0;

    protected override void OnAfterRender()
    {
        count++;
        Console.WriteLine($"OnAfterRender execution count: {count}");
    }

    protected override async Task OnAfterRenderAsync()
    {
        // Initialize JavaScript library
        await JSRuntime.InvokeAsync<bool>("JsFunctions.initializeModal", "Modal has been initialized successfully.");
    }
}

There are a few more files you will need to run this example:

You can get all of them from our GitHub page: nativoplus/BlazorWorkshop

Output

In the console window you can see two messages: the first one is from our OnAfterRender method (notice the WASM: right before the actual message), and the second one comes from the JavaScript function in charge of initializing our modal.

ShouldRender()

This method returns a boolean value. If the value is true, the UI is re-rendered. But even if you override this method, the component will still render once when initialized. Use this to suppress subsequent rendering of the component. Let’s look at an example.

Example

In the following example, a simple counter component is used to trigger a UI refresh when the value count changes. This way, the ShouldRender method gets invoked and we can use it to suppress further rendering.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@page "/switch-counter"

<div class="text-center">
    <h1 class="display-1">@count</h1>

    <button class="btn btn-primary" onclick="@IncrementCounter">Increment</button>
    <br /><br />
    <button class="btn btn-success" onclick="@TurnOn">Turn On</button>
    <button class="btn btn-danger" onclick="@TurnOff">Turn Off</button>
</div>


@functions {
    bool shouldRender = true;
    int count = 0;

    void TurnOff()
    {
        shouldRender = false;
    }

    void TurnOn()
    {
        shouldRender = true;
    }

    void IncrementCounter()
    {
        count++;
    }

    protected override bool ShouldRender()
    {
        return shouldRender;
    }
}

Output

See how easily it is to suppress further rendering of a component with the click of a button! And turn it back on whenever we want to. Also, notice how the Increment button still works even when rendering is turned off, we can see how much the counter has increased by turning it back on.

Additional Methods

These methods aren’t part of the Blazor component lifecycle but they are very useful at different steps of the lifecycle process.

StateHasChanged()

This method is called to indicate that the state of a component has changed. Therefore, Blazor re-renders the calling component. This method can’t be overridden but it can be triggered manually.

Easily use it inside any of your components with the this keyword.

1
this.StateHasChanged()

NOTE

StateHasChanged only triggers a UI refresh for the current component. It does not automatically refresh child or parent components.
Dispose()

Your Blazor components can implement the IDisposable interface. If you do, the Dispose method is available for you to override. This method gets called whenever the calling component is removed from the UI.

Just add the IDisposible interface to your component and implement the Dispose method like this:

1
2
3
4
5
6
7
8
@implements IDisposable

@functions {
    public void Dispose()
    {
        // Do something
    }
}

Simple, right?

Take Away

Blazor provides a number of lifecycle methods that you can easily override. This allows you to execute additional operations at key moments of a component’s lifecycle. Also, most lifecycle methods conveniently have an asynchronous counterpart that you can use for operations that might take a long time to execute. Finally, we saw a couple of methods, StateHasChanged and Dispose, that aren’t part of a component’s lifecycle but can be quite useful at different times of the lifecycle process.

You can get all the examples shown on this post from our GitHub page: nativoplus/BlazorWorkshop