C# Academy · Lekcja

Zarządzanie stanem w Blazor

Zarządzaj współdzielonym stanem za pomocą singletonów usług, Fluxor lub kaskadowego AppState, aby zachować spójność interfejsu między komponentami.

Lekcja 4 z 412 kroki

Zarządzanie stanem w Blazor to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Wyzwania związane z zarządzaniem stanem w Blazorze

Wraz z rozwojem aplikacji Blazor zarządzanie stanem, który musi być współdzielony przez wiele niezależnych komponentów, staje się złożone. Proste prop-drilling przestaje wystarczać — potrzebny jest scentralizowany, reaktywny magazyn stanu.

Prosty stan za pomocą usługi scoped

Najprostsze zarządzanie stanem w Blazorze polega na użyciu usługi scoped, która przechowuje stan i udostępnia zdarzenie umożliwiające komponentom subskrybowanie zmian.

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();
    }
}

Subskrybowanie zmian stanu

Komponenty subskrybują zdarzenie OnChanged usługi stanu i wywołują StateHasChanged, aby ponownie wyrenderować widok. Należy pamiętać o anulowaniu subskrypcji w metodzie 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 jako kontener stanu

Owiń główny layout w CascadingValue zawierający usługę stanu. Wszystkie elementy potomne mogą uzyskać do niej dostęp bez jawnego przekazywania propsów.

@* 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: wzorzec Flux dla Blazora

Fluxor wprowadza do Blazora jednokierunkowy przepływ danych w stylu Redux: State → Component → Action → Reducer → State. To świetne rozwiązanie dla złożonych aplikacji.

// 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));

Używanie Fluxora w komponencie

Wstrzyknij IState<T>, aby odczytywać stan, oraz IDispatcher, aby wysyłać akcje. InheritsFrom<FluxorComponent> (lub mixin) automatycznie subskrybuje zmiany stanu.

@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));
}

Trwałość w localStorage

Zachowuj stan pomiędzy odświeżeniami strony, używając przeglądarkowego localStorage za pośrednictwem interopu JavaScript. Przywracaj go podczas uruchamiania aplikacji.

@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();
}

Pakiet Blazored.LocalStorage

Pakiet Blazored.LocalStorage udostępnia przejrzyste, typowane API dla przeglądarkowego localStorage, bez konieczności ręcznego pisania wywołań interopu JavaScript.

// 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();
}

Stan w adresie URL za pomocą NavigationManager

Użyj parametrów zapytania do przechowywania stanu, który powinien przetrwać odświeżenie strony i umożliwiać dodanie strony do zakładek. Odczytuj je i zapisuj za pomocą NavigationManager oraz konstruktora URI.

@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
                }));
    }
}

Praktyczny przykład: stan koszyka zakupowego

Kompletny wzorzec: usługa scoped CartState ze zdarzeniami, zapisywana w localStorage przy każdej zmianie i przywracana podczas ładowania.

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();
    }
}

Szybkie sprawdzenie

Jakie podejście do zarządzania stanem jest najlepsze dla prostej aplikacji Blazor z niewielką ilością współdzielonego stanu?

Podsumowanie: zarządzanie stanem w Blazorze

Najważniejsze informacje:

  • Usługa scoped + zdarzenie Action: najprostszy współdzielony stan, odpowiedni dla większości aplikacji
  • CascadingValue opakowujący główny layout zapewnia dostęp w całej aplikacji bez prop-drillingu
  • Fluxor: jednokierunkowy przepływ w stylu Redux dla złożonej logiki stanu
  • Trwały zapis stanu w localStorage za pomocą IJSRuntime lub Blazored.LocalStorage
  • Stan w adresie URL (SupplyParameterFromQuery) dla możliwego do dodania do zakładek i udostępniania stanu interfejsu
  • Zawsze anuluj subskrypcję zdarzeń w Dispose, aby zapobiegać wyciekom pamięci
Bezpłatny start

Ucz się C# dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
93
Lekcje
346

Często zadawane pytania

Czy lekcja „Zarządzanie stanem w Blazor” jest bezpłatna?

Tak — pełny tekst „Zarządzanie stanem w Blazor” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Zarządzanie stanem w Blazor”?

Zarządzaj współdzielonym stanem za pomocą singletonów usług, Fluxor lub kaskadowego AppState, aby zachować spójność interfejsu między komponentami. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Zarządzanie stanem w Blazor”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Model komponentów Blazor
  2. Wiązanie danych i obsługa zdarzeń
  3. Komunikacja komponentów i DI
  4. Zarządzanie stanem w Blazor
← Powrót do C# Academy