Blazor Life Cycle Events: Oversimplified
A guide to help you understand the different types
Right from the moment the razor component comes alive, there are a series of methods that get called based on different states of the component. We should have a clear understanding of the flow of the control.
Today, I will teach you different life cycle methods of the razor component and when to call what. There are eight methods that come under this component life cycle.
Let’s start from the beginning by getting to know the architecture of the Blazor page, then learn various synchronous and asynchronous methods.
The following image shows different parts of the razor page:
In some scenarios, we want C# code to run first, and then UI to render. So the objects we are binding in the UI will have data. For example, List
will get filled up with four items first, then the UI will know there are four rows in DataGrid
. On the flip side, sometimes we want UI to render first and then C# code to run.
How to achieve all this? That’s what we are going to learn today. Let’s begin with the first state.
1. OnInitialized and OnInitializedAsync
These two methods are called before the component is rendered, First, we make service calls to fill all the objects which are then bound on the screen.
Let’s see this in action.
Create a Parent
and a Child
component, and add the instance of the Child
component inside Parent
. Refer to the image below:
Parent
look something like this:
Child
component: We are going to use List<string>
to keep the track of the number of events added.
If you run this app, you’ll notice this. When the app starts, these two methods are called first, in the order shown below:
2. OnParametersSet and OnParametersSetAsync
These methods are invoked by the following two triggers:
- Every time new parameters are received from the parent these methods are called.
- Also when the component is loaded for the first time these methods are called right after
OnInitialized()
andOnInitializedAsync()
.
To see this in action, we need to make a few changes in our components.
The Parent
component will now send a parameter named “counter” to the child
component and also be responsible to update the value of this counter. We can achieve this with a button click.
Now for the child
component. It will receive the parameter from the Parent
and show the value of that parameter in UI. This is where we will expose our two methods, OnParametersSet()
and OnParametersSetAsync()
.
Now, observe the series of images below and notice the flow.
Scenario 1: The application runs for the first time, and the order of execution is as follows: OnInitialized()
=> OnInitializedAsync()
=> OnParametersSet()
=> OnParametersSetAsync()
.
Scenario 2: The button on the Parent
component is clicked once, which sends an updated “counter-parameter
” to the child
component, you can see how OnParametersSet()
and OnParametersSetAsync()
gets called again.
Scenario 3: The button is clicked once again, and the same pattern is observed in the child
component.
3. OnAfterRender and OnAfterRenderAsync
These methods are called after the component is rendered. More on this later!
If you look at the syntax shown in the following snippet, you’d see these methods have one boolean parameter firstRender
, the value of firstRender
is true if the component is rendered for the first time. If not, it is false.
In the following couple of images let me show you the execution flow of these two methods. Image 7 shows the flow when the component is rendered for the first time. It calls both methods OnAfterRender()
and OnAfterRenderAsync()
twice.
For the first time, the boolean value of firstRender
is true and then these methods get called again. This time, the value of firstRender
is false.
What happens if the child
component receives a new update from the parent
and renders itself again? The same pattern from image 7 is followed except there are changes in the OnInitialized()
and OnInitializedAsync()
methods.
Now, let’s dig deep to understand what we actually need these methods for.
In order to answer this question, I have to make a few changes to our code. I am going to move the “counter-button
” to the child
component with its OnclickHandler()
, then override OnAfterRender()
. Also, I am logging the “value of the counter” to the console-tab
to cross-verify the current value of the “counter
. Here’s what the child
component will look like after these changes:
Let’s have a look at the parent
component after some code cleanup.
Run the app, and you’ll see how OnAfterRender
actually works.
In the following figure, I am running the application for the first time. As you can see in the Console tab, the value of the counter has been increased by the OnAfterRender()
method, but the UI is not showing the updated value. To put it in simple words, OnAfterRender()
executes code after the UI has been rendered.
Now, what would happen if I click the button? It will render the component again.
First, IncreaseCounter()
will be called. This increases the value of the counter to 2
, then UI is rendered with value 2
, then OnAfterRender
is called, but the UI is not rendered again.
Just to follow through, I will click on the button one more time.
4. StateHasChanged
This life cycle method notifies the UI about the new value and this triggers the rerendering of the component.
- Use: If you are calling async services and want the UI to be rendered again based on new values, you can use this method. Simply put, it notifies the component that the
State
has changed so it will load the component again with a new value.
Let’s first learn why we need StateHasChanged()
.
To demonstrate this, we need something that gets triggered by itself. For that, we can simply use timer
. We will run the timer
until the value of the counter reaches 5
. With each second, we will increase the value of the counter by 1
.
Scenario 1: When we don’t use StateHasChanged()
- Observe how UI threads stay unresponsive to any changes made to counter variables by timer.
Note: Make the following changes in the child
component.
Let’s fire the application and observe the value of the “counter” in the console vs. the value of the “counter
” on UI. UI is not rerendering.
Scenario 2: When we use StateHasChanged()
Now just call StateHasChanged()
in TimeCallBack()
. Refer to line number 6 from the following snippet:
Now see the difference! The UI is rerendering and showing the counter’s increment.
5. ShouldRender
If it returns true, it will forcefully refresh the UI. If not, the updated state of the object will stay in memory but the UI thread will have no idea what the new value is.
Scenario 1: When we return false from ShouldRender()
- Let’s use the same example. This time, override
ShouldRender()
in thechild
component as follows. You’ll see that it returnsfalse
from the method.
If I run this app, then the ShouldRender
method will get called, but it will block UI from being rendered because we are returning false
from the method. Observe how the values in the console are changing, but the UI is unaffected by those changes.
Scenario 2: When we return true from ShouldRender()
The same execution flow will follow, but this time the UI will render updated values.
Conclusion
All right, this was a long article, but I am sure it was helpful. Now we know what different life cycle methods are in Blazor and how they define the state of the component. Once you start designing components, you’ll get a clearer understanding of which lifecycle method to use and when.
Here are a few topics I’ve covered. You can merge to Blazing Blazor’s repository, and learn the following topics.
- Event Callback
- RenderFragment
- CSS Custom Properties
- AttributeSplatting
- CascadingParameter
- CascadingParameter with Name
Thanks for reading!