Del 2 av 8

Razor-syntax & komponenter

Komponenten är Blazors atom. Vi går igenom Razor-syntaxen, hur man skapar egna komponenter, skickar in parametrar och förstår livscykeln.

Lektion 2 — V2. Från färdig sida till egen komponent: vi delar upp UI:t i återanvändbara delar och lär oss att skicka data in och innehåll vidare.

Razor-syntax i ett notskal

Razor är ett sätt att blanda HTML och C# i samma fil. Allting som börjar med @ är C#; resten är HTML.

<h1>Välkommen, @anvandarnamn</h1>

<p>Klockan är @DateTime.Now.ToString("HH:mm")</p>

@if (loggedIn)
{
    <p>Du är inloggad.</p>
}
else
{
    <a href="/login">Logga in</a>
}

<ul>
    @foreach (var item in items)
    {
        <li>@item.Namn — @item.Pris.ToString("C")</li>
    }
</ul>
KonstruktionAnvändning
@variabelSkriv ut värdet inline
@(uttryck)Tvinga parentes för komplext uttryck
@if / @foreach / @switchC#-kontrollflöde i markup
@{ /* kod */ }Block av C# utan output
@@textLiteral @-tecken (escape)

En komponent — anatomi

En komponent är en .razor-fil. Den består typiskt av tre delar:

@* Components/UserCard.razor *@

@* 1. Direktiv — @page, @inject, @using *@
@using BlazorApp.Models

@* 2. Markup med inbäddad C# *@
<div class="card">
    <h3>@User.FullName</h3>
    <p>@User.Email</p>
    <button @onclick="ShowDetails">Visa mer</button>
</div>

@* 3. Code block — fält, parametrar, metoder *@
@code {
    [Parameter, EditorRequired] public User User { get; set; } = default!;
    [Parameter] public EventCallback<User> OnDetailsRequested { get; set; }

    private Task ShowDetails() => OnDetailsRequested.InvokeAsync(User);
}
Filnamnet är komponentnamnet UserCard.razor blir taggen <UserCard /> i andra komponenter. Mappnamnet syns inte i taggen, men @using behövs för att hitta komponenter i andra namespace.

Parametrar — skicka data in

@code {
    [Parameter] public string Title { get; set; } = "";
    [Parameter] public int Count { get; set; }
    [Parameter, EditorRequired] public User User { get; set; } = default!;
    [Parameter(CaptureUnmatchedValues = true)]
    public IDictionary<string, object>? Extra { get; set; }
}

Användning i förälder:

<UserCard User="aktivAnvandare" Title="VIP-kund" Count="3" />

ChildContent — skicka markup in

@* Card.razor *@
<div class="card">
    <div class="card-header">@Header</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter] public RenderFragment? Header { get; set; }
    [Parameter] public RenderFragment? ChildContent { get; set; }
}

Använd komponenten med innehåll mellan taggarna:

<Card>
    <Header><h2>Min titel</h2></Header>
    <ChildContent>
        <p>Här är innehållet i kortet.</p>
        <button>Klick</button>
    </ChildContent>
</Card>

Komponentens livscykel

Blazor anropar speciella metoder vid bestämda tidpunkter. De viktigaste:

MetodAnropasTypisk användning
OnInitialized / OnInitializedAsyncEn gång när komponenten skapasHämta initial data
OnParametersSet / AsyncNär parametrar har satts (även första gången)Reagera på ändrade input-värden
OnAfterRender(firstRender)Efter att DOM:en uppdateratsJS-interop, fokus, externa bibliotek
DisposeNär komponenten tas bortStäda events, timers, subscriptions
@code {
    private List<Product> products = new();

    protected override async Task OnInitializedAsync()
    {
        products = await Http.GetFromJsonAsync<List<Product>>("api/products")
                   ?? new();
    }

    protected override void OnParametersSet()
    {
        // Körs varje gång CategoryId ändras utifrån
        FilterProducts();
    }
}
Vanlig fälla Lägg aldrig async-anrop direkt i konstruktor eller i OnInitialized (utan Async). Använd alltid OnInitializedAsync för data­hämtning.

Code-behind — separera C# från markup

För större komponenter kan koden flyttas till en partial class i en separat .razor.cs-fil:

// Components/UserCard.razor.cs
namespace BlazorApp.Components;

public partial class UserCard
{
    [Parameter, EditorRequired] public User User { get; set; } = default!;

    private async Task ShowDetails()
    {
        // logik här
    }
}

I UserCard.razor behövs då bara markup. Detta gör större komponenter mer lättlästa och underlättar enhetstester.

Referenser

Elektroniska resurser

Böcker

Övningar

Lös övningarna självständigt. Det finns inget facit — lärandet sker i processen.

  1. Bygg en återanvändbar Alert-komponent Den ska ta parametrarna Type (success/warning/error) och Message samt ha en stängknapp som tar bort sig själv. Visa minst 3 instanser med olika typer på en testsida.
  2. UserCard med ChildContent Skapa en UserCard som visar en användares namn och bild, samt accepterar valfritt innehåll via ChildContent. Använd den på en sida för att visa två kort med olika footer-innehåll.
  3. Livscykel-loggning Skapa en komponent som skriver ut i konsollen vid varje livscykelmetod (OnInitialized, OnParametersSet, OnAfterRender etc.). Placera den i en föräldrasida som ändrar en parameter med en knapp och observera ordningen.
  4. Code-behind-refaktorering Ta en existerande komponent med > 30 rader code-block och flytta C#-koden till en partial class i en separat .razor.cs-fil. Verifiera att allt fortfarande fungerar.

Soloprojektor

Projekt 1 — Komponentbibliotek Skapa minst 4 återanvändbara komponenter: Button, Card, Modal, Badge. Varje komponent ska ha parametrar för utseende och ChildContent där det är vettigt. Visa dem alla på en demosida.
Projekt 2 — Mini-CMS (fördjupning) Bygg en sida som visar en lista artiklar (hårdkodade i en lista). Varje artikel renderas av en ArticleCard-komponent som tar in en Article-modell. Lägg till en filterknapp som visar/döljer artiklar utifrån kategori.

← Föregående: Intro Nästa: Data binding & händelser →