Læringsmål
- Placere datahentning i
OnInitializedAsyncvsOnParametersSetAsync. - Forklare forskellen på first render, parameter change og event-driven opdateringer.
- Bruge
StateHasChangedbevidst (og undgå unødige kald). - Kende cascading parameters til tema/API-base der deles i layout.
- Overblik over
ShouldRendersom performance-værktøj.
Hvornår bruger I livscyklus-metoder? Når data afhænger af route/parametre (LoL /champion/{id}), når parent skifter [Parameter], eller når I skal undgå race conditions ved async API-kald fra OpgaverAPI.
Tjek dig selv før du går videre
- Du kan undgå dobbelt-fetch ved første load.
- Du ved hvornår OnParametersSetAsync kører igen.
- Du kan nævne hvorfor CancellationToken bruges ved navigation.
En komponent er ikke «bare HTML» — den har en livscyklus fra første render til destruction. Når parent sender nye parametre (fx valgt champion-id), skal child enten reagere i OnParametersSet eller via bound properties.
Typisk rækkefølge
- SetParametersAsync — parent sender parametre.
- OnInitialized / OnInitializedAsync — én gang ved oprettelse (god til første API-kald).
- OnParametersSet / OnParametersSetAsync — hver gang parametre ændres (god til at re-loade detail når id skifter).
- Event handlers — bruger klikker «Hent næste side» → opdater state → render.
- Dispose — ryd timers, unsubscribe.
Regel: Init til data der kun hænger på siden (statisk intro). OnParametersSet til data der følger id/query fra URL. Events til bruger-initieret refresh («Hent igen»).
Livscyklus-lab
Tryk på trinene — loggen viser hvilke metoder der kører, og hvornår UI opdateres.
- OnInitializedAsync
- OnParametersSet
- Render
- Event (klik)
- Dispose
# Vælg et trin
OnInitializedAsync — første load
@page "/pokemon-lifecycle"
@inject IPokemonService Api
<h1>Starter Pokémon</h1>
<ul>@foreach (var p in mons) { <li>@p.Name</li> }</ul>
@code {
List<Mon> mons = new();
protected override async Task OnInitializedAsync()
{
mons = await Api.GetStarterAsync();
}
record Mon(string Name);
}
Brug async livscyklus-metoder til I/O. Vis loading-state hvis kaldet tager tid — ellers ser brugeren en tom liste.
Elev-fejl → symptom → fix: Data hentes i constructoren — symptom: HttpClient null eller ingen render. Fix: flyt til OnInitializedAsync.
OnParametersSet — route/query ændres
@* ChampionDetail.razor — [Parameter] public string Id *@
@code {
Champion? champ;
protected override async Task OnParametersSetAsync()
{
champ = await Lol.GetChampionAsync(Id);
}
}
Når parent eller router sender nyt Id, kører OnParametersSetAsync igen — uden at komponenten nødvendigvis destrueres.
Hvornår OnParametersSet frem for kun Init? Master/Detail-Pokémon: parent sætter PokemonId ved klik — samme detail-komponent, nyt id. Router med @page "/pokemon/{id:int}" opfører sig tilsvarende.
StateHasChanged og rendering
Vend kortene
Klik for at afsløre — hvornår hvilken livscyklus-hook?
Efter I opdaterer felter uden for en normal event (fx callback fra timer eller JS interop), kan UI mangle opdatering indtil StateHasChanged() kaldes. I de fleste @onclick / @bind-flows sker det automatisk.
protected override bool ShouldRender()
{
// Eksempel: skip render hvis kun intern debug-state ændrede sig
return _visibleChanged;
}
Hvornår ShouldRender? Når en stor LoL-liste re-renderer for ofte (fx parent opdaterer et ur hvert sekund). Returnér false når jeres felter ikke påvirker markup — men brug det målrettet; forkert brug giver «frossen» UI.
EventCallback-timing: Parent opdaterer state i callback → child får nye parametre → OnParametersSet kan køre efter parent’s render. Hvis child også muterer samme state, kan I se et ekstra render-trin — derfor one-way data ned, events op.
Faldgrube: At hente tung data i OnParametersSet og OnInitialized uden guard giver dobbelt API-kald ved første load. Tjek om parametre allerede er sat, eller brug kun OnParametersSetAsync med «first render»-flag.
Cascading values
Layout kan levere fælles værdier (tema, API-base, bruger-context) uden at prop-drille gennem hver komponent:
@* App.razor / Layout *@
<CascadingValue Value="apiBase" Name="ApiBase">
@Body
</CascadingValue>
@* Child *@
@code {
[CascadingParameter(Name = "ApiBase")]
public string ApiBase { get; set; } = "";
}
Hvornår cascading? Når mange dybe børn skal kende samme Mercantec Auth-kontekst, tema eller read-only config — undgå at prop-drille ApiBase gennem fem niveauer. Alternativ: inject IConfiguration eller dedikeret service.
Quiz 1
Hvor loader I typisk første gang data til en sidekomponent med @page?
Quiz 2
Parent ændrer [Parameter] public int PokemonId — hvilken metode skal re-loade detail?
CancellationToken ved navigation
Hvorfor det betyder noget: Eleven klikker Pikachu, skifter hurtigt til LoL-ruten — langsomt Pokémon-detail returnerer stadig og overskriver ny side. CancellationToken stopper unødigt arbejde og race conditions.
protected override async Task OnParametersSetAsync(CancellationToken cancellationToken)
{
loading = true;
try
{
detail = await Lol.GetChampionAsync(Id, cancellationToken);
}
catch (OperationCanceledException)
{
return; // bruger navigerede væk — ikke opdater state
}
finally { loading = false; }
}
Sådan fejler det i praksis: OnInitializedAsync og OnParametersSetAsync kalder begge API ved første load — Network viser to identiske GET. Fix: kun ParametersSet med guard, eller skip fetch i Init hvis Id allerede er sat.
private int _loadedId = -1;
protected override async Task OnParametersSetAsync(CancellationToken ct)
{
if (Id == _loadedId) return;
_loadedId = Id;
detail = await Lol.GetChampionAsync(Id, ct);
}
Mini-opgave
Detail med [Parameter] int Id; log Init vs ParametersSet; eliminer dobbelt-fetch med guard.
Quiz 3
Navigation væk under API-kald — bedste praksis?
Læs hos Microsoft
Prøv med API
- Lav Master/Detail: liste fra
/go/pokemon, detail nårPokemonIdparameter skifter — observer Network for dobbelt-kald. - Sammenlign med LoL-demo: hvornår hentes data ift. navigation?
Baseret på MAGS Blazor-wiki og Microsoft Learn — Blazor.