Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Varning
Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Viktigt!
Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.
För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Optimera återgivningshastigheten för att minimera återgivningsarbetsbelastningen och förbättra UI-svarstiden, vilket kan ge en tiofaldig eller högre förbättring av UI-återgivningshastigheten.
Undvik onödig rendering av komponentunderträd
Du kanske kan ta bort största delen av renderingskostnaden för en överordnad komponent genom att undvika återrenderingen av de underordnade elementen när en händelse inträffar. Du bör endast vara orolig för att undvika att rendera om underträd som är särskilt kostsamma att rendera och orsakar användargränssnittslagg.
Vid körning är komponenter organiserade i en hierarki. En rotkomponent (den första komponenten som lästs in) har delkomponenter. Rotens barn har i sin tur sina egna barnkomponenter och så vidare. När en händelse inträffar, till exempel när en användare väljer en knapp, avgör följande process vilka komponenter som ska återskapas:
- Händelsen skickas till komponenten som renderade händelsens hanterare. När händelsehanteraren har körts återskapas komponenten.
- När en komponent återskapas, tillhandahåller den en ny kopia av parametervärdena till var och en av dess underordnade komponenter.
- När en ny uppsättning parametervärden har tagits emot, avgör Blazor om komponenten ska återskapas. Komponenter återskapas om ShouldRenderreturnerartrue, vilket är standardbeteendet om det inte åsidosätts, och parametervärdena kan ha ändrats, till exempel om de är föränderliga objekt.
De två sista stegen i föregående sekvens fortsätter rekursivt nedåt i komponenthierarkin. I många fall renderas hela underträdet om. Händelser som riktar sig till komponenter på hög nivå kan orsaka dyr rerendering eftersom varje komponent under komponenten på hög nivå måste återskapas.
Om du vill förhindra återrekursion till ett visst underträd använder du någon av följande metoder:
- Kontrollera att underordnade komponentparametrar är av specifika oföränderliga typer†, som string,int,bool, ochDateTime. Den inbyggda logiken för att identifiera ändringar hoppar automatiskt över rerendering om de oföränderliga parametervärdena inte har ändrats. Om en underordnad komponent renderas med<Customer CustomerId="item.CustomerId" />, därCustomerIdär av typenint, så renderas inteCustomer-komponenten om inteitem.CustomerIdförändras.
- Åsidosätt ShouldRender, returnerafalse:- När parametrar är icke-primitiva typer eller oföränderliga typer som inte stöds†, till exempel komplexa anpassade modelltyper eller RenderFragment värden, och parametervärdena inte har ändrats.
- Om du redigerar en komponent med endast användargränssnitt som inte ändras efter den första återgivningen, oavsett parametervärdeändringar.
 
† Mer information finns i logiken för ändringsidentifiering i Blazorreferenskällan (ChangeDetection.cs).
Anmärkning
Dokumentationslänkar till .NET-referenskällan läser vanligtvis in lagringsplatsens standardgren, vilket representerar den aktuella utvecklingen för nästa version av .NET. Om du vill välja en tagg för en specifik version använder du listrutan Välj bland grenar eller taggar. Mer information finns i Så här väljer du en versionstagg för ASP.NET Core-källkod (dotnet/AspNetCore.Docs #26205).
I följande exempel på flygsökningsverktyget används privata fält för att spåra nödvändig information för att identifiera ändringar. Den tidigare inkommande flygidentifieraren (prevInboundFlightId) och den tidigare utgående flygidentifieraren (prevOutboundFlightId) spårar information för nästa potentiella komponentuppdatering. Om någon av flygidentifierarna ändras när komponentens parametrar anges i OnParametersSet, hämtas komponenten på nytt eftersom shouldRender den är inställd på true. Om shouldRender utvärderas till false efter att flygidentifierarna har kontrollerats, undviks en dyr omrendering:
@code {
    private int prevInboundFlightId = 0;
    private int prevOutboundFlightId = 0;
    private bool shouldRender;
    [Parameter]
    public FlightInfo? InboundFlight { get; set; }
    [Parameter]
    public FlightInfo? OutboundFlight { get; set; }
    protected override void OnParametersSet()
    {
        shouldRender = InboundFlight?.FlightId != prevInboundFlightId
            || OutboundFlight?.FlightId != prevOutboundFlightId;
        prevInboundFlightId = InboundFlight?.FlightId ?? 0;
        prevOutboundFlightId = OutboundFlight?.FlightId ?? 0;
    }
    protected override bool ShouldRender() => shouldRender;
}
En händelsehanterare kan också ange shouldRender till true. För de flesta komponenter är det vanligtvis inte nödvändigt att bestämma omrendering på nivån för enskilda händelsehanterare.
Mer information finns i följande resurser:
Virtualisering
När du återger stora mängder användargränssnitt i en loop, till exempel en lista eller ett rutnät med tusentals poster, kan den stora mängden renderingsåtgärder leda till en fördröjning i användargränssnittsrendering. Med tanke på att användaren bara kan se ett litet antal element samtidigt utan att rulla, är det ofta slöseri att ägna tid åt att återge element som för närvarande inte är synliga.
Blazor tillhandahåller den Virtualize<TItem>-komponenten för att skapa utseendet och rullningsbeteendena för en godtyckligt stor lista samtidigt som endast de listobjekt som finns i den aktuella rullningsvyporten renderas. En komponent kan till exempel återge en lista med 100 000 poster men bara betala renderingskostnaden för 20 objekt som är synliga.
Mer information finns i ASP.NET Core Razor-komponentvirtualisering.
Skapa enkla, optimerade komponenter
De flesta Razor komponenter kräver inte aggressiva optimeringsåtgärder eftersom de flesta komponenter inte upprepas i användargränssnittet och inte upprepar sig med hög frekvens. Till exempel visas dirigerbara komponenter med ett @page direktiv och komponenter som används för att återge delar av användargränssnittet på hög nivå, till exempel dialogrutor eller formulär, troligen bara en i taget och endast rerender som svar på en användargest. Dessa komponenter skapar vanligtvis inte hög återgivningsbelastning, så du kan fritt använda valfri kombination av ramverkets funktioner utan att behöva oroa dig för prestandan.
Det finns dock vanliga scenarier där komponenter upprepas i stor skala och ofta resulterar i dåliga användargränssnittsprestanda:
- Stora kapslade formulär med hundratals enskilda element, till exempel indata eller etiketter.
- Rutnät med hundratals rader eller tusentals celler.
- Punktdiagram med miljontals datapunkter.
Om du modellerar varje element, cell eller datapunkt som en separat komponentinstans finns det ofta så många av dem att deras renderingsprestanda blir kritisk. Det här avsnittet innehåller råd om hur du gör sådana komponenter lätta så att användargränssnittet förblir snabbt och dynamiskt.
Undvik tusentals komponentinstanser
Varje komponent är en separat ö som kan renderas oberoende av sina föräldrar och barn. Genom att välja hur användargränssnittet ska delas upp i en hierarki med komponenter tar du kontroll över detaljrikedomen för UI-återgivning. Detta kan resultera i antingen bra eller dåliga prestanda.
Genom att dela upp användargränssnittet i separata komponenter kan mindre delar av användargränssnittet rendreras om när händelser inträffar. I en tabell med många rader som har en knapp i varje rad kanske du bara kan ha den enda radrerendern med hjälp av en underordnad komponent i stället för hela sidan eller tabellen. Varje komponent kräver dock ytterligare minne och processorkostnader för att hantera dess oberoende tillstånd och återgivningslivscykel.
I ett test som utfördes av ASP.NET Core-produktenhetstekniker sågs en renderingskostnad på cirka 0,06 ms per komponentinstans i en Blazor WebAssembly app. Testappen renderade en enkel komponent som accepterar tre parametrar. Internt beror omkostnaderna till stor del på att tillståndet per komponent hämtas från ordlistor och att parametrar skickas och tas emot. Med multiplikation kan du se att lägga till 2 000 extra komponentinstanser skulle lägga till 0,12 sekunder till återgivningstiden och att användargränssnittet skulle börja kännas långsamt för användarna.
Det är möjligt att göra komponenterna enklare så att du kan få fler av dem. En mer kraftfull teknik är dock ofta att undvika att ha så många komponenter att rendera. I följande avsnitt beskrivs två metoder som du kan använda.
Mer information om minneshantering finns i Hantera minne i distribuerade ASP.NET Core-appar på serversidanBlazor.
Infoga underordnade komponenter i sina föräldrar: Överväg följande del av en överordnad komponent som renderar underordnade komponenter i en loop:
<div class="chat">
    @foreach (var message in messages)
    {
        <ChatMessageDisplay Message="message" />
    }
</div>
              ChatMessageDisplay.razor:
<div class="chat-message">
    <span class="author">@Message.Author</span>
    <span class="text">@Message.Text</span>
</div>
@code {
    [Parameter]
    public ChatMessage? Message { get; set; }
}
Föregående exempel fungerar bra om tusentals meddelanden inte visas samtidigt. För att visa tusentals meddelanden samtidigt, överväg i stället för att bortse från den separata ChatMessageDisplay-komponenten. Infoga i stället den underordnade komponenten i den överordnade komponenten. Följande metod undviker per-komponent-överkostnaderna för att rendera så många barnkomponenter, men det sker på bekostnad av att förlora möjligheten att rendera varje barnkomponents markup oberoende av varandra.
<div class="chat">
    @foreach (var message in messages)
    {
        <div class="chat-message">
            <span class="author">@message.Author</span>
            <span class="text">@message.Text</span>
        </div>
    }
</div>
              Definiera återanvändbara RenderFragments i kod: Du kanske separerar ut underkomponenter enbart som ett sätt att återanvända renderingslogik. I så fall kan du skapa återanvändbar renderingslogik utan att implementera ytterligare komponenter. I varje komponents @code-block definierar du en RenderFragment. Rendera fragmentet från valfri plats så många gånger som det behövs:
@RenderWelcomeInfo
<p>Render the welcome content a second time:</p>
@RenderWelcomeInfo
@code {
    private RenderFragment RenderWelcomeInfo = @<p>Welcome to your new app!</p>;
}
Om du vill göra RenderTreeBuilder koden återanvändbar för flera komponenter deklarerar du RenderFragmentpublic och static:
public static RenderFragment SayHello = @<h1>Hello!</h1>;
              SayHello i föregående exempel kan anropas från en orelaterad komponent. Den här tekniken är användbar för att skapa bibliotek med återanvändbara markeringsfragment som renderas utan omkostnader per komponent.
              RenderFragment ombud kan acceptera parametrar. Följande komponent skickar meddelandet (message) till ombudet RenderFragment :
<div class="chat">
    @foreach (var message in messages)
    {
        @ChatMessageDisplay(message)
    }
</div>
@code {
    private RenderFragment<ChatMessage> ChatMessageDisplay = message =>
        @<div class="chat-message">
            <span class="author">@message.Author</span>
            <span class="text">@message.Text</span>
        </div>;
}
Föregående metod återanvänder renderingslogik utan omkostnader per komponent. Metoden tillåter dock inte uppdatering av underträdet i användargränssnittet oberoende av varandra, och den har inte heller möjlighet att hoppa över återgivningen av underträdet i användargränssnittet när dess överordnade renderas eftersom det inte finns någon komponentgräns. Tilldelning till en RenderFragment delegat stöds endast i Razor komponentfiler (.razor).
För ett icke-statiskt fält, en metod eller en egenskap som inte kan refereras till av en fältinitierare, till exempel TitleTemplate i följande exempel, använder du en egenskap i stället för ett fält för RenderFragment:
protected RenderFragment DisplayTitle =>
    @<div>
        @TitleTemplate
    </div>;
Ta inte emot för många parametrar
Om en komponent upprepas mycket ofta, till exempel hundratals eller tusentals gånger, byggs omkostnaderna för att skicka och ta emot varje parameter upp.
Det är ovanligt att för många parametrar kraftigt begränsar prestanda, men det kan vara en faktor. För en TableCell komponent som renderar 4 000 gånger i ett rutnät lägger varje parameter som skickas till komponenten till cirka 15 ms i den totala renderingskostnaden. Att skicka tio parametrar kräver cirka 150 ms och orsakar en UI-återgivningsfördröjning.
Om du vill minska parameterbelastningen paketar du flera parametrar i en anpassad klass. En tabellcellskomponent kan till exempel acceptera ett gemensamt objekt. I följande exempel Data är olika för varje cell, men Options är vanligt för alla cellinstanser:
@typeparam TItem
...
@code {
    [Parameter]
    public TItem? Data { get; set; }
    
    [Parameter]
    public GridOptions? Options { get; set; }
}
Kom dock ihåg att paketering av primitiva parametrar i en klass inte alltid är en fördel. Även om det kan minska antalet parametrar påverkar det också hur ändringsidentifiering och återgivning fungerar. Att skicka icke-primitiva parametrar utlöser alltid en återåtergivning, eftersom Blazor det inte går att veta om godtyckliga objekt har internt föränderligt tillstånd, medan överföring av primitiva parametrar bara utlöser en återåtergivning om deras värden faktiskt har ändrats.
Tänk också på att det kan vara en förbättring att inte ha en tabellcellskomponent, som du ser i föregående exempel, och i stället infoga logiken i den överordnade komponenten.
Anmärkning
När flera metoder är tillgängliga för att förbättra prestandan krävs vanligtvis benchmarking av metoderna för att avgöra vilken metod som ger bäst resultat.
Mer information om generiska typparametrar (@typeparam) finns i följande resurser:
- Razor syntaxreferens för ASP.NET Core
- ASP.NET Core Razor komponenter
- ASP.NET Core Blazor mallbaserade komponenter
Se till att sammanhängande parametrar är fasta
Komponenten CascadingValue har en valfri parameter IsFixed:
- Om IsFixedärfalse(standard) konfigurerar varje mottagare av det överlappande värdet en prenumeration för att ta emot ändringsmeddelanden. Varje[CascadingParameter]är betydligt dyrare än en vanlig[Parameter]på grund av prenumerationsspårningen.
- Om IsFixedärtrue(till exempel<CascadingValue Value="someValue" IsFixed="true">), får mottagarna det ursprungliga värdet men konfigurerar inte en prenumeration för att ta emot uppdateringar.[CascadingParameter]är lätt och inte dyrare än en vanlig[Parameter].
Inställningen IsFixed till true förbättrar prestanda om det finns ett stort antal andra komponenter som tar emot det vidarebefordrade värdet. Ange om möjligt IsFixed till true på överlappande värden. Du kan ange IsFixed till true när det angivna värdet inte ändras över tid.
När en komponent skickas this som ett överlappande värde IsFixed kan även anges till true, eftersom this aldrig ändras under komponentens livscykel:
<CascadingValue Value="this" IsFixed="true">
    <SomeOtherComponents>
</CascadingValue>
Mer information finns i ASP.NET Core Blazor sammanhängande värden och parametrar.
Undvik attributsplätering med CaptureUnmatchedValues
Komponenter kan välja att ta emot "omatchade" parametervärden med hjälp av CaptureUnmatchedValues flaggan:
<div @attributes="OtherAttributes">...</div>
@code {
    [Parameter(CaptureUnmatchedValues = true)]
    public IDictionary<string, object>? OtherAttributes { get; set; }
}
Med den här metoden kan du skicka godtyckliga ytterligare attribut till elementet. Den här metoden är dock dyr eftersom renderaren måste:
- Matcha alla angivna parametrar mot uppsättningen kända parametrar för att skapa en ordlista.
- Håll reda på hur flera kopior av samma attribut skriver över varandra.
Använd CaptureUnmatchedValues där komponentrenderingsprestanda inte är kritiska, till exempel komponenter som inte upprepas ofta. För komponenter som renderas i stor skala, till exempel varje objekt i en stor lista eller i cellerna i ett rutnät, försök att undvika sammankoppling av attributer.
För mer information, se ASP.NET Core Blazor attributsspridning och godtyckliga parametrar.
Implementera SetParametersAsync manuellt
En betydande källa till omkostnader för rendering per komponent är att skriva de inkommande parametervärdena till [Parameter]-egenskaper. Renderaren använder reflektion för att skriva parametervärdena, vilket kan leda till dåliga prestanda i stor skala.
I vissa extrema fall kanske du vill undvika reflektionen och implementera din egen parameterinställningslogik manuellt. Detta kan vara tillämpligt när:
- En komponent återges mycket ofta, till exempel när det finns hundratals eller tusentals kopior av komponenten i användargränssnittet.
- En komponent accepterar många parametrar.
- Du upptäcker att omkostnaderna för att ta emot parametrar har en observerbar inverkan på UI-svarstiden.
I extrema fall kan du åsidosätta komponentens virtuella SetParametersAsync metod och implementera din egen komponentspecifika logik. I följande exempel undviks avsiktligt ordlistesökningar:
@code {
    [Parameter]
    public int MessageId { get; set; }
    [Parameter]
    public string? Text { get; set; }
    [Parameter]
    public EventCallback<string> TextChanged { get; set; }
    [Parameter]
    public Theme CurrentTheme { get; set; }
    public override Task SetParametersAsync(ParameterView parameters)
    {
        foreach (var parameter in parameters)
        {
            switch (parameter.Name)
            {
                case nameof(MessageId):
                    MessageId = (int)parameter.Value;
                    break;
                case nameof(Text):
                    Text = (string)parameter.Value;
                    break;
                case nameof(TextChanged):
                    TextChanged = (EventCallback<string>)parameter.Value;
                    break;
                case nameof(CurrentTheme):
                    CurrentTheme = (Theme)parameter.Value;
                    break;
                default:
                    throw new ArgumentException($"Unknown parameter: {parameter.Name}");
            }
        }
        return base.SetParametersAsync(ParameterView.Empty);
    }
}
I den föregående koden, genom att returnera basklassen SetParametersAsync, kommer den normala livscykelmetoden att köras utan att parametrarna tilldelas igen.
Som du ser i föregående kod är det komplicerat och besvärligt att åsidosätta SetParametersAsync och tillhandahålla anpassad logik, så vi rekommenderar vanligtvis inte att du använder den här metoden. I extrema fall kan det förbättra renderingsprestanda med 20–25%, men du bör bara överväga den här metoden i de extrema scenarier som anges tidigare i det här avsnittet.
Utlös inte händelser för snabbt
Vissa webbläsarhändelser utlöses väldigt ofta. Till exempel onmousemove och onscroll kan utlösa tiotals eller hundratals gånger per sekund. I de flesta fall behöver du inte utföra användargränssnittsuppdateringar ofta. Om händelser utlöses för snabbt kan du skada UI-svarstiden eller förbruka för hög CPU-tid.
I stället för att använda inbyggda händelser som snabbt utlöses bör du överväga att använda JS interop för att registrera ett återanrop som utlöses mindre ofta. Följande komponent visar till exempel musens position men uppdateras bara högst en gång var 500 ms:
@implements IDisposable
@inject IJSRuntime JS
<h1>@message</h1>
<div @ref="mouseMoveElement" style="border:1px dashed red;height:200px;">
    Move mouse here
</div>
@code {
    private ElementReference mouseMoveElement;
    private DotNetObjectReference<MyComponent>? selfReference;
    private string message = "Move the mouse in the box";
    [JSInvokable]
    public void HandleMouseMove(int x, int y)
    {
        message = $"Mouse move at {x}, {y}";
        StateHasChanged();
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            selfReference = DotNetObjectReference.Create(this);
            var minInterval = 500;
            await JS.InvokeVoidAsync("onThrottledMouseMove", 
                mouseMoveElement, selfReference, minInterval);
        }
    }
    public void Dispose() => selfReference?.Dispose();
}
Motsvarande JavaScript-kod registrerar DOM-händelselyssnaren för musrörelse. I det här exemplet använder händelselyssnaren Lodashs throttle funktion för att begränsa antalet anrop:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
<script>
  function onThrottledMouseMove(elem, component, interval) {
    elem.addEventListener('mousemove', _.throttle(e => {
      component.invokeMethodAsync('HandleMouseMove', e.offsetX, e.offsetY);
    }, interval));
  }
</script>
Undvik att rendera om efter att ha hanterat händelser utan ändringar av tillståndet
Komponenter kommer från ComponentBase, som automatiskt anropar StateHasChanged efter att komponenternas händelsehanterare har anropats. I vissa fall kan det vara onödigt eller oönskat att utlösa en rerender när en händelsehanterare anropas. En händelsehanterare kanske till exempel inte ändrar komponenttillståndet. I dessa scenarier kan appen använda IHandleEvent gränssnittet för att styra beteendet Blazorför händelsehantering.
Anmärkning
Metoden i det här avsnittet hanterar inte undantag inom felgränser. För mer information och demonstrationskod som stöder felgränser genom att anropa ComponentBase.DispatchExceptionAsync, se AsNonRenderingEventHandler + ErrorBoundary = oväntat beteende (dotnet/aspnetcore #54543).
För att förhindra omritningar för alla händelsehanterare i en komponent, implementera IHandleEvent och tillhandahåll ett IHandleEvent.HandleEventAsync-uppdrag som anropar händelsehanteraren utan att anropa StateHasChanged.
I följande exempel utlöser ingen händelsehanterare som läggs till komponenten en rerender, så HandleSelect det resulterar inte i en rerender när den anropas.
              HandleSelect1.razor:
@page "/handle-select-1"
@using Microsoft.Extensions.Logging
@implements IHandleEvent
@inject ILogger<HandleSelect1> Logger
<p>
    Last render DateTime: @dt
</p>
<button @onclick="HandleSelect">
    Select me (Avoids Rerender)
</button>
@code {
    private DateTime dt = DateTime.Now;
    private void HandleSelect()
    {
        dt = DateTime.Now;
        Logger.LogInformation("This event handler doesn't trigger a rerender.");
    }
    Task IHandleEvent.HandleEventAsync(
        EventCallbackWorkItem callback, object? arg) => callback.InvokeAsync(arg);
}
Förutom att förhindra omrenderingar efter att en händelsehanterare har körts globalt, är det möjligt att förhindra omrenderingar efter en enskild händelsehanterare genom att använda följande metod.
Lägg till följande EventUtil klass i en Blazor app. Statiska åtgärder och funktioner överst i EventUtil klassen tillhandahåller hanterare som täcker flera kombinationer av argument och returtyper som Blazor används vid hantering av händelser.
              EventUtil.cs:
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
public static class EventUtil
{
    public static Action AsNonRenderingEventHandler(Action callback)
        => new SyncReceiver(callback).Invoke;
    public static Action<TValue> AsNonRenderingEventHandler<TValue>(
            Action<TValue> callback)
        => new SyncReceiver<TValue>(callback).Invoke;
    public static Func<Task> AsNonRenderingEventHandler(Func<Task> callback)
        => new AsyncReceiver(callback).Invoke;
    public static Func<TValue, Task> AsNonRenderingEventHandler<TValue>(
            Func<TValue, Task> callback)
        => new AsyncReceiver<TValue>(callback).Invoke;
    private record SyncReceiver(Action callback) 
        : ReceiverBase { public void Invoke() => callback(); }
    private record SyncReceiver<T>(Action<T> callback) 
        : ReceiverBase { public void Invoke(T arg) => callback(arg); }
    private record AsyncReceiver(Func<Task> callback) 
        : ReceiverBase { public Task Invoke() => callback(); }
    private record AsyncReceiver<T>(Func<T, Task> callback) 
        : ReceiverBase { public Task Invoke(T arg) => callback(arg); }
    private record ReceiverBase : IHandleEvent
    {
        public Task HandleEventAsync(EventCallbackWorkItem item, object arg) => 
            item.InvokeAsync(arg);
    }
}
Anropa EventUtil.AsNonRenderingEventHandler för att anropa en händelsehanterare som inte utlöser en återgivning när den anropas.
I följande exempel:
- Genom att välja första knappen, som anropar HandleClick1, utlöses en omrendering.
- Att välja den andra knappen, som triggar HandleClick2, initierar ingen omrendering.
- Om du väljer den tredje knappen, som anropar HandleClick3, utlöser det inte en omrendering utan använder händelseargument (MouseEventArgs).
              HandleSelect2.razor:
@page "/handle-select-2"
@using Microsoft.Extensions.Logging
@inject ILogger<HandleSelect2> Logger
<p>
    Last render DateTime: @dt
</p>
<button @onclick="HandleClick1">
    Select me (Rerenders)
</button>
<button @onclick="EventUtil.AsNonRenderingEventHandler(HandleClick2)">
    Select me (Avoids Rerender)
</button>
<button @onclick="EventUtil.AsNonRenderingEventHandler<MouseEventArgs>(HandleClick3)">
    Select me (Avoids Rerender and uses <code>MouseEventArgs</code>)
</button>
@code {
    private DateTime dt = DateTime.Now;
    private void HandleClick1()
    {
        dt = DateTime.Now;
        Logger.LogInformation("This event handler triggers a rerender.");
    }
    private void HandleClick2()
    {
        dt = DateTime.Now;
        Logger.LogInformation("This event handler doesn't trigger a rerender.");
    }
    
    private void HandleClick3(MouseEventArgs args)
    {
        dt = DateTime.Now;
        Logger.LogInformation(
            "This event handler doesn't trigger a rerender. " +
            "Mouse coordinates: {ScreenX}:{ScreenY}", 
            args.ScreenX, args.ScreenY);
    }
}
Förutom att implementera IHandleEvent gränssnittet kan användning av andra metodtips som beskrivs i den här artikeln också bidra till att minska oönskade återgivningar efter att händelser har hanterats. Till exempel kan att åsidosätta ShouldRender i målkomponentens underordnade komponenter användas för att styra omrendering.
Undvik att återskapa delegater för många återkommande element eller komponenter
Blazoråterkapandet av delegeringar av lambda-uttryck för element eller komponenter i en loop kan leda till dålig prestanda.
Följande komponent som visas i händelsehanteringsartikeln återger en uppsättning knappar. Varje knapp tilldelar en delegerad till sin @onclick-händelse, vilket är bra om det inte finns många knappar att rendera.
              EventHandlerExample5.razor:
@page "/event-handler-example-5"
<h1>@heading</h1>
@for (var i = 1; i < 4; i++)
{
    var buttonNumber = i;
    <p>
        <button @onclick="@(e => UpdateHeading(e, buttonNumber))">
            Button #@i
        </button>
    </p>
}
@code {
    private string heading = "Select a button to learn its position";
    private void UpdateHeading(MouseEventArgs e, int buttonNumber)
    {
        heading = $"Selected #{buttonNumber} at {e.ClientX}:{e.ClientY}";
    }
}
@page "/event-handler-example-5"
<h1>@heading</h1>
@for (var i = 1; i < 4; i++)
{
    var buttonNumber = i;
    <p>
        <button @onclick="@(e => UpdateHeading(e, buttonNumber))">
            Button #@i
        </button>
    </p>
}
@code {
    private string heading = "Select a button to learn its position";
    private void UpdateHeading(MouseEventArgs e, int buttonNumber)
    {
        heading = $"Selected #{buttonNumber} at {e.ClientX}:{e.ClientY}";
    }
}
Om ett stort antal knappar återges med föregående metod påverkas återgivningshastigheten negativt, vilket leder till en dålig användarupplevelse. För att rendera ett stort antal knappar med ett återanrop för klickhändelser, använder följande exempel en samling av knappobjekt som tilldelar varje knapps @onclick-delegat till dess Action-delegat. Följande metod kräver Blazor inte att alla knappdelegater återskapas varje gång knapparna återges:
              LambdaEventPerformance.razor:
@page "/lambda-event-performance"
<h1>@heading</h1>
@foreach (var button in Buttons)
{
    <p>
        <button @key="button.Id" @onclick="button.Action">
            Button #@button.Id
        </button>
    </p>
}
@code {
    private string heading = "Select a button to learn its position";
    private List<Button> Buttons { get; set; } = new();
    protected override void OnInitialized()
    {
        for (var i = 0; i < 100; i++)
        {
            var button = new Button();
            button.Id = Guid.NewGuid().ToString();
            button.Action = (e) =>
            {
                UpdateHeading(button, e);
            };
            Buttons.Add(button);
        }
    }
    private void UpdateHeading(Button button, MouseEventArgs e)
    {
        heading = $"Selected #{button.Id} at {e.ClientX}:{e.ClientY}";
    }
    private class Button
    {
        public string? Id { get; set; }
        public Action<MouseEventArgs> Action { get; set; } = e => { };
    }
}
ASP.NET Core