C# Academy · Lektion

Tillståndshantering i Blazor

Hantera delat tillstånd med tjänste-singletons, Fluxor eller kaskadiserat AppState för att hålla användargränssnittet konsekvent mellan komponenter.

Lektion 4 av 412 steg

Tillståndshantering i Blazor är en gratis lektion i C# Academy på CoddyKit. Detta är lektion 4 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för C# Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i C# Academy innehåller totalt 4 lektioner.

Utmaningar med state-hantering i Blazor

När Blazor-appar växer blir det komplext att hantera state som måste delas av många orelaterade komponenter. Enkel prop-drilling räcker inte längre; ni behöver ett centraliserat, reaktivt state-lager.

Enkel state-hantering med en scoped-tjänst

Den enklaste formen av state-hantering i Blazor är en scoped-tjänst som lagrar state och exponerar en händelse som komponenter kan prenumerera på för att få ändringar.

public class CartState
{
    private readonly List<CartItem> _items = new();
    public IReadOnlyList<CartItem> Items => _items;
    public int Count => _items.Sum(i => i.Quantity);

    public event Action? OnChanged;

    public void Add(Product p)
    {
        var existing = _items.FirstOrDefault(i => i.ProductId == p.Id);
        if (existing is not null) existing.Quantity++;
        else _items.Add(new CartItem { ProductId = p.Id, Name = p.Name, Price = p.Price });
        OnChanged?.Invoke();
    }
}

Prenumerera på state-ändringar

Komponenter prenumererar på state-tjänstens OnChanged-händelse och anropar StateHasChanged för att renderas om. Kom ihåg att avsluta prenumerationen i Dispose.

@inject CartState Cart
@implements IDisposable

<p>Cart: @Cart.Count items</p>

@code {
    protected override void OnInitialized()
    {
        Cart.OnChanged += OnCartChanged;
    }

    private void OnCartChanged()
    {
        InvokeAsync(StateHasChanged);
    }

    public void Dispose() =>
        Cart.OnChanged -= OnCartChanged;
}

CascadingValue som state-container

Omslut root-layouten med en CascadingValue som innehåller er state-tjänst. Alla underordnade komponenter kan komma åt den utan uttrycklig vidarebefordran av props.

@* MainLayout.razor *@
@inject CartState Cart

<CascadingValue Value="Cart">
    @Body
</CascadingValue>

@* Any nested component: *@
@code {
    [CascadingParameter]
    public CartState Cart { get; set; } = default!;

    private void Buy(Product p) => Cart.Add(p);
}

Fluxor: Flux-mönstret för Blazor

Fluxor tillför ett enkelriktat dataflöde i Redux-stil till Blazor: State → Component → Action → Reducer → State. Det passar utmärkt för komplexa applikationer.

// dotnet add package Fluxor.Blazor.Web

// State record
[FeatureState]
public record CounterState(int Count = 0);

// Actions
public record IncrementAction(int Amount = 1);

// Reducers
public static class CounterReducers
{
    [ReducerMethod]
    public static CounterState Reduce(CounterState state, IncrementAction action)
        => state with { Count = state.Count + action.Amount };
}

// Registration:
builder.Services.AddFluxor(opt =>
    opt.ScanAssemblies(typeof(Program).Assembly));

Använda Fluxor i en komponent

Injicera IState<T> för att läsa state och IDispatcher för att skicka actions. InheritsFrom<FluxorComponent> (eller mixinen) prenumererar automatiskt på state-ändringar.

@inherits FluxorComponent
@inject IState<CounterState> CounterState
@inject IDispatcher Dispatcher

<p>Count: @CounterState.Value.Count</p>
<button @onclick="Increment">+1</button>
<button @onclick="() => Dispatcher.Dispatch(new IncrementAction(5))">+5</button>

@code {
    private void Increment()
        => Dispatcher.Dispatch(new IncrementAction(1));
}

Persistens i localStorage

Bevara state mellan siduppdateringar genom webbläsarens localStorage via JavaScript interop. Återställ det när appen startar.

@inject IJSRuntime JS

@code {
    private async Task SaveStateAsync()
    {
        var json = JsonSerializer.Serialize(_state);
        await JS.InvokeVoidAsync("localStorage.setItem", "appState", json);
    }

    protected override async Task OnInitializedAsync()
    {
        var json = await JS.InvokeAsync<string?>("localStorage.getItem", "appState");
        if (json is not null)
            _state = JsonSerializer.Deserialize<AppState>(json) ?? new();
    }

    private AppState _state = new();
}

Paketet Blazored.LocalStorage

Paketet Blazored.LocalStorage tillhandahåller ett rent, typat API ovanpå webbläsarens localStorage utan att ni behöver skriva JS interop-anrop manuellt.

// dotnet add package Blazored.LocalStorage
builder.Services.AddBlazoredLocalStorage();

@inject ILocalStorageService LocalStorage

@code {
    protected override async Task OnInitializedAsync()
    {
        _cart = await LocalStorage.GetItemAsync<List<CartItem>>("cart") ?? new();
    }

    private async Task SaveCartAsync()
    {
        await LocalStorage.SetItemAsync("cart", _cart);
    }

    private List<CartItem> _cart = new();
}

URL-state med NavigationManager

Använd frågeparametrar för state som ska överleva en siduppdatering och kunna sparas som bokmärke. Läs och skriv dem via NavigationManager och URI-byggaren.

@inject NavigationManager Nav
@page "/products"

@code {
    [SupplyParameterFromQuery] public string? Search { get; set; }
    [SupplyParameterFromQuery] public int Page { get; set; } = 1;

    private void UpdateSearch(string s)
    {
        Nav.NavigateTo(
            Nav.GetUriWithQueryParameters(
                new Dictionary<string, object?>
                {
                    [nameof(Search)] = s,
                    [nameof(Page)]   = 1
                }));
    }
}

Verklighetsnära exempel: state för kundvagn

Ett komplett mönster: en scoped CartState-tjänst med händelser, som sparas i localStorage vid ändringar och återställs vid inläsning.

public class CartState
{
    private readonly ILocalStorageService _storage;
    private List<CartItem> _items = new();
    public event Action? OnChanged;

    public CartState(ILocalStorageService storage) => _storage = storage;

    public async Task InitAsync()
    {
        _items = await _storage.GetItemAsync<List<CartItem>>("cart") ?? new();
    }

    public async Task AddAsync(Product p)
    {
        var item = _items.FirstOrDefault(i => i.ProductId == p.Id);
        if (item is not null) item.Quantity++;
        else _items.Add(new CartItem { ProductId = p.Id, Name = p.Name });
        await _storage.SetItemAsync("cart", _items);
        OnChanged?.Invoke();
    }
}

Snabbkontroll

Vilken metod för state-hantering passar bäst för en enkel Blazor-app med begränsat delat state?

Sammanfattning: state-hantering i Blazor

Viktiga slutsatser:

  • Scoped-tjänst + Action-händelse: enklaste formen av delat state, bra för de flesta appar
  • En CascadingValue runt roten ger åtkomst i hela appen utan prop-drilling
  • Fluxor: enkelriktat flöde i Redux-stil för komplex state-logik
  • Spara state i localStorage med IJSRuntime eller Blazored.LocalStorage
  • URL-state (SupplyParameterFromQuery) för bokmärkningsbart och delbart UI-state
  • Avsluta alltid prenumerationer på händelser i Dispose för att förhindra minnesläckor
Gratis att börja

Lär dig C# med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
93
Lektioner
346

Vanliga frågor

Är lektionen ”Tillståndshantering i Blazor” gratis?

Ja – hela texten till ”Tillståndshantering i Blazor” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i C# Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i C# Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Tillståndshantering i Blazor”?

Hantera delat tillstånd med tjänste-singletons, Fluxor eller kaskadiserat AppState för att hålla användargränssnittet konsekvent mellan komponenter. Ni övar på C# Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig C# Academy?

Du behöver inga förkunskaper. Utbildningen i C# Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.

Hur lång tid tar lektionen ”Tillståndshantering i Blazor”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här C# Academy-lektionen?

Ja. Varje C# Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Blazor-komponentmodellen
  2. Databindning och händelsehantering
  3. Kommunikation mellan komponenter och DI
  4. Tillståndshantering i Blazor
← Tillbaka till C# Academy