As we saw in the previous article, the .razor file consists of an HTML and C# code in the same file. But if we want, we can split this file into two files, one for the HTML logic and another one for the C# logic. So, in this article, we are going to learn how to use Partial Classes to split the .razor file, and additionally, we are going to talk about using the RenderFragment parameters to send content to the component. Finally, we have to mention the lifecycle in the Blazor WebAssembly applications.

That said, we are going to explain different lifecycle methods we can use while developing a Blazor application.

To download the source code for this article, you can visit the Blazor partial classes repository.

For the complete navigation for this series, you can visit the Blazor Series page.

We are going to divide this article into the following topics:

Let’s get going.

Blazor Partial Classes Implementation

With the .NET Core 3.1 framework, we can separate our .razor file into two separate (but still connected) files. To accomplish that, we have to add a new class to the .razor file. Let’s use the Home.razor file for this example.

If we inspect this file, we can see the C# logic in the @code part. This is a small file and having both parts in the same file is not an issue at all. But as our projects grow, we are ending up with more and more HTML and C# logic and that can become hard to read and maintain. So, it is good practice to separate these two parts. To do that, we have to create a new class in the Component folder and name it Home.razor.cs:

Partial class creation

As we can see, the Visual Studio attaches this file to the Home.razor file. But, if we inspect our new class, we are going to see an error. That’s because this new class has to be a partial one. So, let’s add a partial keyword:

public partial class Home
{
}

Now, we can open the Home component file, and cut all the code from the @code section and remove the @code directive:

<div style="text-align:center">
    <h1 style="color: @Color">
        @Title
    </h1>
    <p>
        Feel free to 
        <a href="https://www.redbubble.com/people/vpecanac/works/44764889-code-maze-merch?asc=u" target="_blank">visit our shop</a>
        any time you want.
    </p>
    <p>
        <img @attributes="AdditionalAttributes" class="img-fluid" />
    </p>   
</div>

And finally, paste the code in the Home class:

public partial class Home
{
    [Parameter]
    public string Title { get; set; }

    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> AdditionalAttributes { get; set; }

    [CascadingParameter]
    public string Color { get; set; }
}

Of course, we have to add the using Microsoft.AspNetCore.Components statement to remove all the attribute errors.

Excellent.

If we build and run our application, everything should work as it supposed to, without a single problem.

One more thing. We can use multiple partial classes if we need them. The important part is to name them differently, for example, Home.razor.data.cs, Home.razor.internal.cs etc. Of course, all of these files have to be partial.

Using RenderFragment Parameters in Blazor WebAssembly

In addition to sending parameters to the component, we can send the content as well. This is very useful when we have an HTML markup that we want to use inside the component. It is a bad solution trying to send the HTML code through the parameters to the component because it would be so hard to maintain and it is not readable at all. The better solution is to use RenderFragment.

Let’s see, how we can use the RenderFragment parameter in our Home component.

The first thing we are going to do is to modify the Home class:

public partial class Home
{
    [Parameter]
    public string Title { get; set; }

    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> AdditionalAttributes { get; set; }

    [CascadingParameter]
    public string Color { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }
}

So, there is another property of type RenderFragment and we decorate it with the [Parameter] attribute. The Blazor will use this property to attach embedded content. This content may be plain text, HTML elements, or any other Blazor component.

The next thing we want to do is to modify the Home component file, by replacing the code inside the first p tag with our newly created property:

<div style="text-align:center">
    <h1 style="color: @Color">
        @Title
    </h1>
    <p>
        @ChildContent
    </p>
    <p>
        <img @attributes="AdditionalAttributes" class="img-fluid" />
    </p>    
</div>

And finally, let’s modify the Index file:

@page "/"
@using BlazorProducts.Client.Components 

    <Home Title="Welcome to the BlazorProducts.Client application." @attributes="AdditionalAttributes">
        Feel free to
        <a href="https://www.redbubble.com/people/vpecanac/works/44764889-code-maze-merch?asc=u" target="_blank">visit our shop</a>
        any time you want.
    </Home>

@code{
    public Dictionary<string, object> AdditionalAttributes { get; set; } = new Dictionary<string, object>
    {
        { "src", "/assets/products.png" },
        { "alt", "products image for the Home component" }
    };
}

As you can see, we’ve placed the content we want to send to the component, between the open and close component tags. By doing that, we’re binding that content to the ChildContent property inside the Home component.

As soon as we do that, we can start our application and confirm that it runs as expected.

Now, we have to mention one thing here. The RenderFragment property must have the ChildContent name for this to work. So, to see this in action, let’s modify the name of the ChildContent property to the VisitShopContent in both .cs and .razor files:

public partial class Home
{
    [Parameter]
    public string Title { get; set; }

    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> AdditionalAttributes { get; set; }

    [CascadingParameter]
    public string Color { get; set; }

    [Parameter]
    public RenderFragment VisitShopContent { get; set; }
}
<div style="text-align:center">
    <h1 style="color: @Color">
        @Title
    </h1>
    <p>
        @VisitShopContent
    </p>
    <p>
        <img @attributes="AdditionalAttributes" class="img-fluid" />
    </p>
    
</div>

Now, if we start our application, we don’t get any error messages, but we don’t get the content either:

Missing content for RenderFragment

To make this work, we have to explicitly specify the name of the RenderFragment property in the Index.razor file:

@page "/"
@using BlazorProducts.Client.Components 

    <Home Title="Welcome to the BlazorProducts.Client application." @attributes="AdditionalAttributes">
        <VisitShopContent>
            Feel free to
            <a href="https://www.redbubble.com/people/vpecanac/works/44764889-code-maze-merch?asc=u" target="_blank">visit our shop</a>
            any time you want.
        </VisitShopContent>
    </Home>

@code{
    public Dictionary<string, object> AdditionalAttributes { get; set; } = new Dictionary<string, object>
    {
        { "src", "/assets/products.png" },
        { "alt", "products image for the Home component" }
    };
}

Now, if we start our application once again, the missing part reappears. This way, we can use multiple RenderFragment parameters for a single component.

Blazor Lifecycle Methods

Blazor has several actions that trigger in the certain stages of the application’s lifecycle. These methods can be synchronous or asynchronous. If we want to use them, we have to override them in our code. Of course, we have to use async lifecycle methods only if we have async actions in these methods.

SetParameterAsync

This method will trigger first, as soon as the component is created. All the parameters sent to the component will be stored in the ParameterView object. So, if we want to take some async actions before any parameter value is assigned to the respective properties, this is the place to do it:

public override Task SetParametersAsync(ParameterView parameters)
{
    return base.SetParametersAsync(parameters);
}

OnInitialized and OnInitializedAsync

These methods trigger as soon as the component initializes and receives all the parameters from the parent component:

protected override void OnInitialized()
{
    base.OnInitialized();
}

protected override Task OnInitializedAsync()
{
    return base.OnInitializedAsync();
}

OnParameterSet and OnParameterSetAsync

These methods trigger after the component receives its parameters and their values are assigned to their respective properties. These methods will trigger repeatedly as soon as the parameter’s value gets updated:

protected override void OnParametersSet()
{
    base.OnParametersSet();
}
protected override Task OnParametersSetAsync()
{
    return base.OnParametersSetAsync();
}

OnAfterRender and OnAfterRenderAsync

As soon as the component finishes rendering, these methods get called. We should use this stage to perform additional initialization steps using the rendered content. These methods have the firstRender parameter set to true only the first time the method executes. Every other time the value is false:

protected override void OnAfterRender(bool firstRender)
{
    base.OnAfterRender(firstRender);
}

protected override Task OnAfterRenderAsync(bool firstRender)
{
    return base.OnAfterRenderAsync(firstRender);
}

StateHasChanged

We can call this method whenever we want to notify Blazor that something has changed in our component and we want to rerender that component. For example, if want to show or hide our modal window, based on the user’s actions, we have to rerender our component every time the modal receives an order to show or hide. To see this exact example in practice, you can read our Blazor WebAssembly Forms article.

ShouldRender

We can use this method to suppress UI refreshing. This method is called each time the component is rendered. Also, no matter if we set this method to return false, the component is always initially rendered:

protected override bool ShouldRender()
{
    return base.ShouldRender();
}

Dispose

Even though this is not strictly one of the Blazor’s lifecycle methods, we can use it to do something after the component is removed from its parent’s render tree. If a component implements an IDisposable interface it will execute the Dispose method as soon as we navigate away from that component:

public partial class SignalRCharts : IDisposable
{
    private HubConnection _hubConnection;

    ...

    public void Dispose()
    {
        _hubConnection.DisposeAsync();
    }
}

This is just part of the code, where we dispose of our SignalR hub connection as soon as we navigate away from our component.

Lifecycle Example

To see this in a concrete example, we are going to modify the Counter.razor file and create a new CounterPrint component. So, let’s first create a new component and modify it:

<h1>@Title</h1>

<p>Current count: @CurrentCount</p>

@code {
    [Parameter]
    public string Title { get; set; }
    [Parameter]
    public int CurrentCount { get; set; }

    protected override void OnInitialized()
    {
        Console.WriteLine($"OnInitialized => Title: {Title}, CurrentCount: {CurrentCount}");
    }

    protected override void OnParametersSet()
    {
    	Console.WriteLine($"OnParameterSet => Title: {Title}, CurrentCount: {CurrentCount}");
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if(firstRender)
        {
            Console.WriteLine("This is the first render of the component");
        }
    }

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

So, we have two parameters and our lifecycle methods that print some output to the console.

Now, let’s modify the Counter.razor file:

@page "/counter"

<CounterPrint CurrentCount="currentCount" Title="Counter" />

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

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

As you can see, we are using our new component here and pass the Title and the CurrentCountvalues to it. The CurrentCount increments every time we click the Click me button.

Now, let’s start the application open the developer console window, and navigate to the Counter page:

Blazor application Lifecycle initial load with RenderFragment parameters

We can see that on initial load all three lifecycle methods trigger and we can confirm this is the first render. But as soon as we click the Click me button:

Second render with parameter change

Only the OnParameterSet method triggers because the CurrentCount parameter is updated. Of course, we can confirm this is not the first render anymore. Additionally, the current count in the UI is updated from 0 to 1.

Now, let’s stop the application, and modify the CounterPrint component by returning false in the ShouldRender method:

protected override bool ShouldRender()
{
    return false;
}

We can start the application again, press F12, navigate to the counter and press the Click me button:

Component is not rendering

This time the UI doesn’t update the current count value and thus we can see how to control the render actions on our pages.

Conclusion

In this article, we have learned:

  • How to use partial classes to separate the C# and HTML logic in a component
  • How to use RenderFragment parameters to pass dynamic content to the component
  • About lifecycle methods and their execution in the Blazor application

In the next article, we are going to talk about Routing and how to navigate to different pages.