Udostępnij przez


Omówienie zarządzania stanem ASP.NET Core Blazor

W tym artykule i innych artykułach w tym węźle opisano typowe podejścia do obsługi danych (stanu) użytkownika podczas korzystania z aplikacji i sesji przeglądarki, w tym podczas prerenderingu serwera.

Typowym wymaganiem podczas Blazor tworzenia aplikacji jest udostępnianie stanu między składnikami:

  • Element nadrzędny do elementu podrzędnego: składnik nadrzędny przekazuje stan do składnika podrzędnego przy użyciu parametrów.
  • Podrzędne do elementu nadrzędnego: składnik podrzędny umożliwia powiązanie danych ze stanem lub zapewnia stan za pośrednictwem wywołań zwrotnych.
  • Element nadrzędny do elementów potomnych: stan udziałów nadrzędnych ze wszystkimi elementami potomnymi przy użyciu wartości kaskadowych.
  • Aplikacja dla całej aplikacji: stan jest współużytkowany w całej aplikacji przy użyciu skonfigurowanych usług stanu aplikacji.
  • Na obwód: stan jest współużytkowany dla określonego obwodu przy użyciu usług stanu aplikacji o określonym zakresie.

Stan utrwalonego może wymagać przetrwania odświeżeń stron, wznowionych obwodów i wstępnegoenderowania. Stan często wymaga centralnego zarządzania, śledzenia i testowania. Lokalizacje i techniki utrwalania stanu są bardzo zmienne.

Blazor nie zapewnia kompleksowego, opinii zarządzania stanem. Produkty i usługi kontenerów stanu innych firm, które bezproblemowo współpracują z usługami Blazor, takimi jak Flux, Redux i MobX, spełniają praktycznie wszelkie wymagania dotyczące aplikacji.

W pozostałej części tego artykułu omówiono ogólne strategie zarządzania stanem dla dowolnego typu Blazor aplikacji.

Zarządzanie stanem przy użyciu adresu URL

W przypadku przejściowych danych reprezentujących stan nawigacji modeluje dane jako część adresu URL. Przykłady stanu użytkownika modelowane w adresie URL to:

  • Identyfikator wyświetlanej jednostki.
  • Bieżący numer strony w siatce stronicowanej.

Zawartość paska adresu przeglądarki jest zachowywana:

  • Jeśli użytkownik ręcznie ponownie załaduje stronę.
  • Tylko scenariusze po stronie serwera: jeśli serwer internetowy stanie się niedostępny, a użytkownik musi ponownie załadować stronę w celu nawiązania połączenia z innym serwerem.

Aby uzyskać informacje na temat definiowania wzorców URL za pomocą @page dyrektywy, zobacz routing ASP.NET CoreBlazor.

Usługa kontenera stanu w pamięci operacyjnej

Zagnieżdżone składniki zazwyczaj wiążą dane przy użyciu chained bind, jak opisano w powiązaniu danych ASP.NET CoreBlazor. Zagnieżdżone i niezagnieżdżone składniki mogą udostępniać dostęp do danych przy użyciu zarejestrowanego kontenera stanu w pamięci. Niestandardowa klasa kontenera stanu może używać przypisywalnego obiektu Action do powiadamiania składników w różnych częściach aplikacji o zmianach stanu. W poniższym przykładzie:

  • Para składników używa kontenera stanu do śledzenia właściwości.
  • Jeden element w poniższym przykładzie jest zagnieżdżony w innym elemencie, ale zagnieżdżanie nie jest wymagane, aby to podejście działało.

Ważne

W przykładzie w tej sekcji pokazano, jak utworzyć usługę kontenera stanu w pamięci, zarejestrować usługę i użyć jej w składnikach. W tym przykładzie dane nie są utrwalane bez dalszego programowania. W przypadku trwałego przechowywania danych kontener stanu musi przyjąć podstawowy mechanizm magazynu, który przetrwa, kiedy pamięć przeglądarki zostanie wyczyszczona. Można to osiągnąć za pomocą localStorage/sessionStorage lub innej technologii.

StateContainer.cs:

public class StateContainer
{
    private string? savedString;

    public string Property
    {
        get => savedString ?? string.Empty;
        set
        {
            savedString = value;
            NotifyStateChanged();
        }
    }

    public event Action? OnChange;

    private void NotifyStateChanged() => OnChange?.Invoke();
}

Aplikacje po stronie klienta (Program plik):

builder.Services.AddSingleton<StateContainer>();

Aplikacje po stronie serwera (Program plik, ASP.NET Core na platformie .NET 6 lub nowszym):

builder.Services.AddScoped<StateContainer>();

Aplikacje po stronie serwera (Startup.ConfigureServices zazwyczaj Startup.csw programie .NET 6 lub starszym):

services.AddScoped<StateContainer>();

Shared/Nested.razor:

@implements IDisposable
@inject StateContainer StateContainer

<h2>Nested component</h2>

<p>Nested component Property: <b>@StateContainer.Property</b></p>

<p>
    <button @onclick="ChangePropertyValue">
        Change the Property from the Nested component
    </button>
</p>

@code {
    protected override void OnInitialized()
    {
        StateContainer.OnChange += StateHasChanged;
    }

    private void ChangePropertyValue()
    {
        StateContainer.Property = 
            $"New value set in the Nested component: {DateTime.Now}";
    }

    public void Dispose()
    {
        StateContainer.OnChange -= StateHasChanged;
    }
}

StateContainerExample.razor:

@page "/state-container-example"
@implements IDisposable
@inject StateContainer StateContainer

<h1>State Container Example component</h1>

<p>State Container component Property: <b>@StateContainer.Property</b></p>

<p>
    <button @onclick="ChangePropertyValue">
        Change the Property from the State Container Example component
    </button>
</p>

<Nested />

@code {
    protected override void OnInitialized()
    {
        StateContainer.OnChange += StateHasChanged;
    }

    private void ChangePropertyValue()
    {
        StateContainer.Property = "New value set in the State " +
            $"Container Example component: {DateTime.Now}";
    }

    public void Dispose()
    {
        StateContainer.OnChange -= StateHasChanged;
    }
}

Powyższe składniki implementują IDisposable, a delegaty OnChange są odsubskrybowywane w metodach Dispose, które są wywoływane przez framework podczas usuwania składników. Aby uzyskać więcej informacji, zobacz usuwanie komponentów w ASP.NET Core Razor.

Kaskadowe wartości i parametry

Użyj kaskadowych wartości i parametrów , aby zarządzać stanem, przepływając dane ze składnika przodka Razor do składników malejących:

  • Aby korzystać ze stanu w wielu komponentach.
  • Jeśli istnieje tylko jeden obiekt stanu najwyższego poziomu do przechowywania.

Wartości kaskadowe na poziomie głównym z CascadingValueSource<TValue> zezwalają na Razor powiadomienia subskrybenta składnika o zmienionych wartościach kaskadowych. Aby uzyskać więcej informacji i przykład roboczy, zobacz przykład NotifyingDalek w ASP.NET Core Blazor kaskadowych wartości i parametrów.

Obsługa modyfikacji stanu spoza Blazorkontekstu synchronizacji

W przypadku korzystania z niestandardowej usługi zarządzania stanem, w której chcesz obsługiwać modyfikacje stanu spoza kontekstu synchronizacji Blazor (na przykład z czasomierza lub usługi w tle), wszystkie komponenty wykorzystujące muszą umieścić wywołanie StateHasChanged w ComponentBase.InvokeAsync. Dzięki temu powiadomienie o zmianie jest obsługiwane w kontekście synchronizacji programu renderatora.

Gdy usługa zarządzania stanem nie wywołuje StateHasChanged w kontekście synchronizacji Blazor, zgłaszany jest następujący błąd:

System.InvalidOperationException: "Bieżący wątek nie jest skojarzony z Dispatcherem. Użyj metody InvokeAsync(), aby przełączyć proces wykonawczy na dyspozytor podczas wywoływania renderowania lub aktualizacji stanu komponentu.

Aby uzyskać więcej informacji i przykład sposobu rozwiązywania tego błędu, zobacz ASP.NET Core Razor rendering składnika.