Budowanie aplikacji frontendowych obecnie składa się z układania małych części widoku oraz jego logiki w taki sposób, aby całość była czytelna i możliwie reużywalna. Nie inaczej jest w Blazorze.
Komponenty są jego podstawowymi elementami z których zbudowana jest każda aplikacja. Służą do wyświetlania oraz zarządzania stanem części UI wraz z logiką jaka na niej występuje. Mogą być zagnieżdżane, reużywalne oraz współdzielone między projektami.
Każdy komponent składa się z pliku .razor w którym znajduje się kod C# oraz HTML. Przykładowy komponent:
@inject IUserService userService
<div class="card w-25">
<div class="card-header font-weight-bold">User Info</div>
<div class="card-body">
<div>@User.Id</div>
<div>@User.UserName</div>
<div>@User.FirstName</div>
<div>@User.LastName</div>
<div>
<button @onclick="RemoveUser">Remove</button>
</div>
</div>
</div>
@code {
[Parameter]
public User User { get; set; }
public void RemoveUser() {
userService.Remove(User.Id);
}
}
Kod C# w komponencie musi być poprzedzony znakiem @ lub sekcja @code, pozostałe części komponentu traktowane są jako tagi HTML. Sekcja @code służy do opisywania logiki, która jest wykonywana w komponencie. Wszystkie zadeklarowane pola będą dostępne w nim poprzez odwołanie się jako @nazwa_pola, dodatkowo możemy obsłużyć zdarzenia takie jak @onclick w danym tagu poprzez napisanie metody oraz podanie jej nazwy jako wartość @onclick. Pola posiadające accessory get i set wymuszają ponowne narysowanie komponentu przy zmianie wartości, natomiast oznaczenie pola atrybutem [Parameter] mogą być przekazywane z komponentu rodzina do dziecka. Przykładowy kod komponentu rodzica:
@inject IUserService userService
<div>
@foreach(var user in users)
{
<UserInfo User="@user" />
}
</div>
@code {
private IList<User> users;
protected override async Task OnInitializedAsync()
{
users = userService.GetAll();
}
}
W komponencie Users tworzone są komponenty UserInfo do których przekazywany jest parametr User z obiektem użytkownika na podstawie którego później następuje wyświetlenie danych.
Lista użytkowników ładowana jest w specjalnej metodzie, która uruchamiana jest w momencie tworzenia komponentu. Jest to jedna z metod powiązanych z cyklem życia komponentu. Oto schemat obrazujący cykl życia komponentu:

Podczas tworzenia komponentu, gdy zostają w nim ustawiane parametry wywoływana jest metoda SetParametersAsync, następnie, gdy jest już zainicjalizowany wywoływane są metody OnInitialized i OnInitializedAsync. Po samym narysowaniu komponentu mamy jeszcze metodę OnAfterRender oraz jej asynchroniczną wersje OnAfterRenderAsync. Jeżeli chcemy na podstawie parametrów ustawić stan komponentu to metoda OnInitialized jest odpowiednim miejscem, natomiast w sytuacji, gdy chcemy aktualizować wewnętrzny stan komponentu po każdej zmianie parametru z zewnątrz powinniśmy użyć metody OnParametersSet.
Komponenty Users i UserInfo korzystają z zewnętrznego serwisu implementujacego interfejs IUserService. Jest to możliwe przy wykorzystaniu dyrektywy @inject, która pozwala na wstrzykniecie serwisu zarejestrowanego podczas tworzenia aplikacji w Program.cs. Nie jest to jedyna dyrektywa, która pozwala na rozszerzanie działania komponentu. Inne dyrektywy to:
Nazwa | Wykorzystanie | Opis |
page | @page „/user/{id}” | Ustawia ścieżkę routing do komponentu poprzez którą możliwe jest wyświetlenie go pod endpointem /user/{id} |
implements | @implements IDisposable | Pozwala na implementowanie interfejsu w komponencie, w tym przypadku na utworzenie komponentu, który może być disposable. |
inherits | @inherits ComponentBase | Umożliwia dziedziczenie komponentów, dyrektywa jest przydatna, gdy chcemy współdzielić wspólne cechy komponentów. |
typeparam | @typeparam TItem | Odpowiednik typów generycznych dla komponentów. Możliwe jest utworzenie komponentu, który będzie miał te same zachowanie dla kilku różnych typów. |
using | @using System.Linq | Umożliwia odwolywanie się do elementów z podanej przestrzeni nazw w tym wypadku System.Linq bez podawania pełnej ścieżki. Alternatywnie można użyć tej dyrektywy w _Imports.razor, aby zastosować ją globalnie. |
layout | @layout MainLayout | Ustawienie layoutu w jakim ma renderować się komponent, w tym wypadku będzie to MainLayout. Komponenty layoutów muszą dziedziczyć z LayoutComponentBase. |
attribute | @attribute [Authorize] | Pozwala na ustawienie atrybutu dla komponentu. Przykładowym atrybutem może być Authorize bądź AllowAnonymous. |
Przedstawiłem podstawowe informacje o komponentach, dodatkowo warto dokładniej przyjrzeć się temu w którym momencie występuje odrysowanie komponentu i jak możemy nim sterować oraz jak zwracać informacje o zaistnieniu zdarzenia poprzez interfejs EventCallback<T>. Pamiętaj, że podział na komponenty jest równie ważny, zachęcam do zapoznania się z wpisem jak ja to robię, aby uniknąć późniejszych problemów.
Jeżeli uznasz ten post za przydatny to proszę udostępnij go innym, natomiast jak chcesz być na bieżąco i otrzymywać informacje o moich aktywnościach przed innymi to zapraszam Cię do newslettera na którym regularnie udostępniam przedpremierowo artykuły, materiały wideo i wiele więcej.