A component instance has a lifecycle that starts when Blazor Server instantiates the component class and renders the component view along with its child views. The lifecycle continues with property change detection, as Blazor Server checks to see when the properties change and update the view. The lifecycle ends when Blazor Server destroys the component instance and removes its rendered template from the DOM.
Blazor Server is designed to let you interact with the initialization process, respond to updates when property changes, and clean up before GC collects instances.
You can download the example code used in this topic on GitHub.
Before working with lifecycle hooks, you should have a basic understanding of the following:
You can respond to events in the lifecycle of a component by overriding one or more of the lifecycle hook methods in the Microsoft.AspNetCore.Components.ComponentBase
class. The hooks give you the opportunity to act on a component instance at the appropriate moment, as Blazor Server creates, updates, or destroys that instance.
You don't have to override all (or any) of the lifecycle hooks, just the ones you need. Here is an example of hooking a method to a component's lifecycle event.
@page "/hooking-method" <h3>@Welcome</h3> @code { private string Welcome = ""; // interfere on init process of this component protected override void OnInitialized() { Welcome = "Welcome to Blazor School!"; } }
After your application instantiates a component by calling its constructor (you won't see this constructor in high level component), Blazor Server calls the hook methods you have implemented at the appropriate point in the lifecycle of that instance.
Blazor Server executes hook methods in the following sequence. You can use them to perform the following kinds of operations.
Hook method | Purpose | Timing |
---|---|---|
OnInitialized() |
Initialize the component after Blazor Server renders the component. |
Called at the beginning of the render process. Server triggered. |
OnInitializedAsync() |
Same as OnInitialized but for async operations. |
Called after Server triggered. |
OnParametersSet() |
Respond to property changes. |
Called after Server triggered. |
OnParametersSetAsync() |
Same as OnParametersSet() but for async operations. |
Called after Server triggered. |
OnAfterRender(true) |
Render the component on the client side. |
Called after Client triggered. |
OnAfterRenderAsync(true) |
Same as OnAfterRender(true) but for async operations. |
Called after Client triggered. |
OnAfterRender(false) |
Response to the StateHasChanged() method. |
Called after whenever Client triggered. |
OnAfterRenderAsync(false) |
Same as OnAfterRender(false) but for async operations. |
Called after whenever Client triggered. |
Dispose() |
To use this method, the component must have @implements IDisposable directive. This method responds to clean up the component. |
Called after user navigates to another page or the component is being cleaned up. Client triggered. |
The example at the top of the page demonstrates the use of lifecycle hooks by calling them one by one and showing the log to the UI. You can look at HookMethodsCallingSequenceExample.razor
component.
Use the OnInitialized()
method to perform the following initialization tasks.
NavigationManager.LocationChanged
.The OnInitialized()
method cannot perform the following tasks.
Refer to the InitilizeAndDisposeComponentExample.razor
component for a demonstration.
protected override void OnInitialized() { Car = new() { Color = "Red" }; Car.OnColorChanged += OnColorChangedHandler; Colors = new() { "Red", "Green", "Blue", "Violet" }; }
To avoid memory leaks, you need to cleanup the resources before GC collects the component. You need to use @implement
directive to implement IDisposable
interface. Put cleanup code logic in Dispose()
, the logic that must run before Blazor Server destroys the component.
This is the place to free resources that won't be garbage-collected automatically. You risk memory leaks if you neglect to do so.
Refer to the InitilizeAndDisposeComponentExample.razor
component for a demonstration.
public void Dispose() { Car.OnColorChanged -= OnColorChangedHandler; }
OnParametersSet()
method of a component whenever it detects changes to the [Parameter]
properties. This means that whenever the property is changed by the parent component, the OnParametersSet()
method of the child parent will be fired. The CarDetail.razor
demonstrated this by monitoring the OnParametersSet()
hook.protected override void OnParametersSet() { Log += "CarDetail detected parameter changed <br>"; }
The example component, CarDetail.razor
, has one input parameter Car
.
[Parameter] public Car Car { get; set; }
The host DetectParameterChangesExample.razor
pass parameter as follows.
<CarDetail Car="Car"></CarDetail>
Here is an example in action as the user makes changes.
The log entries appear as the Car.Color
property changes.
Note: TheCar.Color
is being manipulated by the host, not theCarDetail.razor
itself.
In some scenarios, the child will modify a property and the parent component will not get notice that the property has changed. As Blazor Server traverses the DOM hierarchy during change detection, Blazor Server will not traverse back to the parent to increase performance. You need to use StateHasChanged();
to tell Blazor Server to render the caller component again.
Add an input to the CarDetail.razor
to make the color editable from the car detail component.
<input @bind-value="@Car.Color" />
The @bind
directive will create a binding between the value attribute of the input tag and the Car.Color
property. The next step is to display the color in the parent component. Now, verify that the parent component is not updated when the child modifies the color.
Add a button to call StateHasChanged();
in the parent component.
<button @onclick="() => StateHasChanged()">Re-render</button>
Verify that the parent component is updated when click the button.
event
keyword.Car.cs
and convert the Color
property to a full property.private string _color; public string Color { get => _color; set => _color = value; }
Declare a delegate OnColorChangedHandler
. The delegate should take 2 parameters, the first one will be an object sender
(sender of the event), the second one should be the data for the event, in this case, that is string color
.
public delegate void OnColorChangedHandler(object sender, string color);
Declare an event for the delegate.
public event OnColorChangedHandler OnColorChanged;
Fire the event whenever the Color
property changes.
public string Color { get => _color; set { _color = value; OnColorChanged?.Invoke(this, value); } }
Navigate to the parent component, use @implements
directive to implement the IDisposable
interface.
@implements IDisposable
Override the OnInitialized()
method and add a Dispose()
method in the @code{}
section.
private void OnCarColorChanged(object sender, string color) { StateHasChanged(); } protected override void OnInitialized() { Car.OnColorChanged += OnCarColorChanged; } public void Dispose() { Car.OnColorChanged -= OnCarColorChanged; }
The results are illuminating.