Component Inheritance Patterns
In this lesson, you will learn how to leverage C# class inheritance to centralize shared logic and lifecycle behaviors across your Blazor components, reducing code duplication.
When building large-scale Blazor applications, you often find yourself repeating the same boilerplate—such as injecting common services, initializing logging, or managing specific subscription lifecycles. Rather than copy-pasting this logic into every .razor file, you can define a ComponentBase class in C#.
The Base Component Pattern
To implement this, you create a standard C# class that inherits from Microsoft.AspNetCore.Components.ComponentBase. Once defined, your Razor files can use the @inherits directive to gain access to all the properties, methods, and lifecycle hooks defined in that base class.
Consider a scenario where several components need to track a UserSession and perform common cleanup. Instead of repeating this logic, you create a base class:
public abstract class AuthenticatedComponent : ComponentBase
{
[Inject] protected IUserService UserService { get; set; } = default!;
protected bool IsAuthorized { get; private set; }
protected override async Task OnInitializedAsync()
{
IsAuthorized = await UserService.IsAuthenticatedAsync();
}
}
Now, any Razor component can inherit this behavior:
@inherits AuthenticatedComponent
@if (IsAuthorized)
{
<p>Welcome back, user!</p>
}
Why Use Inheritance Over Composition?
While composition (using services or partial classes) is often preferred for complex UI logic, inheritance is highly effective for "cross-cutting concerns" that rely on lifecycle methods like OnInitializedAsync or OnParametersSet. By placing these in a base class, you ensure that every inheriting component automatically respects the required initialization sequence without needing to manually invoke base methods or repeat service injections.
Remember that Razor components support single inheritance. This means your base class should be designed as a specialized template for a family of components rather than a dumping ground for unrelated features. Keep your base classes focused on shared lifecycle management and dependency access.
Key Takeaway: Use component inheritance to define a unified base class that encapsulates repetitive lifecycle logic and common dependency injections, ensuring your components remain DRY and consistent across your application.