Blazor aplikacija je spora? 7 uzroka i kako ih popraviti

Blazor aplikacija koči na klik, tablica se smrzava ili server troši sve više memorije? Sedam najčešćih uzroka, s kodom prije i poslije, za .NET 10.

Vlado Pandžić

Vlado Pandžić · Osnivač · Senior .NET arhitekt
Objavljeno · 4 min čitanja

Blazor aplikacija na početku leti. Nekoliko ekrana, malo podataka, sve se odaziva trenutno. Godinu dana kasnije klik na gumb kasni, tablica s narudžbama se smrzne na par sekundi, a server troši sve više memorije kako dan odmiče.

Blazor je rijetko sam kriv. Gotovo uvijek je u pitanju jedan od ovih sedam uzroka, i svi se mogu popraviti bez prepisivanja aplikacije. Svaki je ovdje s kodom, za .NET 10.

Prvo: izmjerite što se renderira

Najčešće iznenađenje je koliko puta se komponenta renderira. Privremeni log to pokaže u minuti:

protected override void OnAfterRender(bool firstRender)
    => Logger.LogDebug("{Component} rendered", GetType().Name);   // privremeno, samo dok mjerite

Ako se nakon jednog klika u logu pojavi pedeset redaka, našli ste problem broj jedan.

1. Sve se ponovno renderira na svaki klik

Blazor ponovno renderira dijete kad mu se promijene parametri. Ali kad je parametar složen objekt, poput cijele narudžbe, Blazor ne može znati je li se unutra nešto promijenilo, pa renderira svaki put. Jednostavni tipovi poput int i string ne ponovno renderiraju komponentu dok im se vrijednost ne promijeni.

@* prije: cijeli objekt, pa se red renderira na svaku promjenu roditelja *@
<OrderRow Order="order" />

@* poslije: samo ono što red prikazuje *@
<OrderRow Number="@order.Number" Customer="@order.CustomerName" Total="@order.Total" />

Kad to nije moguće, komponenta može sama odlučiti smije li se renderirati:

private int lastVersion;

protected override bool ShouldRender()
{
    var changed = Order.Version != lastVersion;   // renderiraj samo kad se narudžba stvarno promijenila
    lastVersion = Order.Version;
    return changed;
}

2. Liste bez @key

Kad se lista promijeni, Blazor bez @key uspoređuje retke po redoslijedu. Jedan umetnut red na vrhu znači da se svi ispod njega ponovno renderiraju, a stanje unutar redaka može završiti u krivom retku.

@foreach (var order in orders)
{
    <OrderRow @key="order.Id" Number="@order.Number" Total="@order.Total" />
}

3. Tablice s tisućama redaka

Pet tisuća redaka renderiranih odjednom znači pet tisuća komponenti u memoriji i na ekranu, iako korisnik vidi njih dvadeset. Virtualize renderira samo ono što je vidljivo:

<Virtualize Items="orders" Context="order">
    <OrderRow @key="order.Id" Number="@order.Number" Total="@order.Total" />
</Virtualize>

QuickGrid isto radi s Virtualize="true", a za stvarno velike podatke oba mogu dohvaćati retke s poslužitelja dio po dio.

4. Podaci se učitavaju dvaput

S prerenderingom se OnInitializedAsync izvršava dvaput: jednom na poslužitelju za prvi prikaz, i još jednom kad komponenta postane interaktivna. To znači dva ista upita u bazu i treptaj na ekranu. U .NET-u 10 to rješava jedan atribut:

@code {
    [PersistentState]
    public List<OrderSummary>? Orders { get; set; }

    protected override async Task OnInitializedAsync()
    {
        Orders ??= await OrderService.GetOpenAsync();   // drugi put su podaci već tu
    }
}

5. StateHasChanged prečesto

Komponenta koja prati cijene, statuse ili poruke u stvarnom vremenu lako završi s desecima rendera u sekundi. Korisnik ne vidi razliku između 4 i 40 osvježavanja u sekundi, ali poslužitelj i preglednik je itekako osjete.

protected override void OnInitialized()
{
    Prices.Changed += OnPriceChanged;
    renderTimer = new Timer(_ =>
    {
        if (!dirty) return;
        dirty = false;
        InvokeAsync(StateHasChanged);                  // najviše četiri rendera u sekundi
    }, null, 250, 250);
}

private void OnPriceChanged(object? sender, PriceChangedEventArgs e) => dirty = true;  // samo zabilježi promjenu

6. Memorija poslužitelja koja samo raste

Komponenta koja se pretplati na događaj ili pokrene timer, a to nikad ne otkaže, nikad ne umire. Na Blazor Serveru to znači da memorija raste sa svakim korisnikom i svakim otvorenim ekranom, sve do restarta.

@implements IDisposable

@code {
    public void Dispose()
    {
        Prices.Changed -= OnPriceChanged;              // bez ovoga komponenta ostaje u memoriji
        renderTimer?.Dispose();
    }
}

7. Pogrešan način renderiranja za ekran

U .NET-u 10 svaka stranica može imati svoj način renderiranja. Interaktivni Server je odličan za interne ekrane na dobroj mreži, ali na lošoj vezi svaki klik čeka mrežu. Stranice koje se samo čitaju ne trebaju interaktivnost uopće.

@* MjesecniIzvjestaj.razor: samo čitanje, statično renderiranje bez veze prema poslužitelju *@
@page "/izvjestaji/mjesecni"

@* Narudzbe.razor: interaktivni ekran *@
@page "/narudzbe"
@rendermode InteractiveServer

Koji način za koji ekran, opisali smo u tablici na stranici Blazor specijalizacija.

Kojim redom

  1. IzmjeritiKoliko se puta što renderira
  2. RazbitiManje komponente, jednostavni parametri
  3. VirtualiziratiVelike liste i tablice
  4. OčistitiDispose i način renderiranja

Često spor Blazor ekran uopće nije problem Blazora, nego upita iza njega. Ako se ekran dugo učitava, a malo renderira, pogledajte članak o EF Core performansama.

Kako mi radimo

ProCoding je .NET studio iz Splita i Blazor isporučujemo u produkciju od 2020., od softvera za proizvodnju električnih automobila do upravljanja baterijskim spremnicima. Kroz Blazor health check pronalazimo koji od ovih uzroka koči vašu aplikaciju i dajemo popis popravaka po prioritetu. Prvi korak je besplatni razgovor od 30 minuta.

Izvori

Ovaj članak služi općem informiranju i nije pravni, porezni, financijski ni drugi stručni savjet. Scenariji, primjeri i izračuni su ilustrativni. Uvjeti korištenja i odricanje od odgovornosti.

Povezani članci

© 2026 ProCoding — Sva prava pridržana.Impresum i privatnostUvjeti korištenjaSplit, Hrvatska