Blazor Component Fundamentals
Welcome to the Blazor Component Fundamentals tutorial. This guide will walk you through the core concepts of building and managing components in Blazor applications.
What are Blazor Components?
Blazor components are reusable pieces of UI, written in C# and Razor syntax. They encapsulate HTML, CSS, and C# logic to create interactive web user interfaces. Components are the building blocks of any Blazor application.
Key Characteristics:
- Reusability: Design components once and use them across your application.
- Encapsulation: Each component manages its own state, logic, and rendering.
- Composition: Build complex UIs by composing smaller, simpler components.
- State Management: Components can hold and update their own state.
Creating Your First Component
Components in Blazor typically have a .razor
file extension. This file contains a combination of HTML markup and C# code.
Example: A Simple Counter Component
Let's create a basic counter component named SimpleCounter.razor
.
@page "/simplecounter"
<h1>Simple Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
Explanation:
@page "/simplecounter"
: This directive makes the component routable, meaning it can be accessed directly via the URL/simplecounter
.- HTML Markup: Standard HTML elements like
<h1>
,<p>
, and<button>
define the UI structure. @currentCount
: This is an expression that renders the value of thecurrentCount
variable. Blazor automatically updates the UI when this value changes.@onclick="IncrementCount"
: This is an event handler. When the button is clicked, theIncrementCount
method in the@code
block is executed.@code { ... }
: This block contains C# code for the component, including properties, methods, and event handlers.
Component Parameters
Components can accept parameters to customize their behavior and appearance. This is achieved using the [Parameter]
attribute.
Example: A Greeter Component
Create a Greeter.razor
component that accepts a Name
parameter.
<h3>Hello, @Name!</h3>
@code {
[Parameter]
public string Name { get; set; } = "World";
}
Using the Greeter Component:
You can use this component in another component (e.g., Index.razor
) like this:
<PageTitle>Welcome</PageTitle>
<h1>Welcome to Our App!</h1>
<Greeter Name="Blazor User" />
<Greeter /> <!-- Uses the default value "World" -->
Explanation:
[Parameter] public string Name { get; set; } = "World";
: Defines a public propertyName
that can be set from the parent component. A default value is provided.- When using
<Greeter Name="Blazor User" />
, theName
parameter is explicitly set. - When using
<Greeter />
, the default value "World" is used because no parameter was provided.
Component Lifecycle
Components have a defined lifecycle with various methods that are called at specific points. Understanding these methods is crucial for managing component state and interactions.
Common Lifecycle Methods:
Method | Description |
---|---|
OnInitialized() |
Called when the component is initialized, after parameters are set. Good for initial data fetching. |
OnInitializedAsync() |
Asynchronous version of OnInitialized() . Use for asynchronous initialization logic. |
OnParametersSet() |
Called when component parameters have been set or changed. Called after OnInitialized() and after subsequent parameter updates. |
OnParametersSetAsync() |
Asynchronous version of OnParametersSet() . |
ShouldRender() |
Allows you to control whether the component should re-render. Return false to skip rendering. |
OnAfterRender(bool firstRender) |
Called after the component has been rendered. firstRender is true if this is the first render. Useful for interacting with the DOM or JavaScript. |
OnAfterRenderAsync(bool firstRender) |
Asynchronous version of OnAfterRender() . |
OnInitialized()
and OnAfterRender()
are the most frequently used lifecycle methods. Use OnAfterRender
with caution to avoid infinite render loops.
Component Events and Callbacks
Components can emit events to notify their parent components about specific actions or data changes. This is typically done using EventCallback
.
Example: A Button Component with a Click Event
Create a CustomButton.razor
component.
<button class="btn btn-secondary" @onclick="NotifyClicked">@Text</button>
@code {
[Parameter]
public string Text { get; set; } = "Click";
[Parameter]
public EventCallback OnClick { get; set; }
private void NotifyClicked()
{
// Invoke the callback passed from the parent
OnClick.InvokeAsync();
}
}
Using the CustomButton Component:
In a parent component, you can listen for the OnClick
event:
<h2>Event Handling Example</h2>
<CustomButton Text="Save" OnClick="HandleSaveClick" />
<CustomButton Text="Cancel" OnClick="HandleCancelClick" />
@if (!string.IsNullOrEmpty(message))
{
<p>@message</p>
}
@code {
private string message;
private void HandleSaveClick()
{
message = "Save action triggered!";
}
private void HandleCancelClick()
{
message = "Cancel action triggered.";
}
}
Component Hierarchy and Rendering
Blazor uses a component tree structure. When a component re-renders, Blazor efficiently updates the DOM using a diffing algorithm. Components can render other components, creating nested structures.
Rendering Logic:
- Blazor re-renders a component when its state changes (e.g., a parameter is updated, or an event handler modifies internal state).
- You can manually trigger a re-render using
StateHasChanged()
. - The
ShouldRender()
method provides fine-grained control over when rendering occurs.
Best Practices
- Keep components small and focused on a single responsibility.
- Use parameters for configuration and
EventCallback
for communication up the component tree. - Leverage lifecycle methods appropriately for initialization and side effects.
- Avoid unnecessary calls to
StateHasChanged()
. - Consider asynchronous operations carefully within lifecycle methods.
By mastering Blazor components, you gain the power to build complex, dynamic, and maintainable web applications with C#.