この記事とこのノードの他の記事では、ユーザーがアプリを使用している間や、サーバーのプリレンダリング中など、ブラウザー セッション間でユーザーのデータ (状態) を維持するための一般的な方法について説明します。
Blazorアプリ開発時の一般的な要件は、コンポーネント間で状態を共有することです。
- 親から子: 親コンポーネントは、パラメーターを使用して子コンポーネントに状態を渡します。
- 子から親へ: 子コンポーネントは、その状態へのデータ バインディングを有効にするか、コールバックを介して状態を提供します。
- 親から子孫へ: 親は、カスケード値を使用して、すべての子孫と状態を共有します。
- アプリ全体: 状態は、構成されたアプリ状態サービスを使用してアプリ全体で共有されます。
- 回線ごと: 状態は、スコープ付きアプリ状態サービスを使用して特定の回線で共有されます。
永続化された状態では、ページの更新、再開された回線、およびプリレンダリングを維持する必要がある場合があります。 状態は、多くの場合、集中管理、追跡、テストを必要とします。 状態を保持するための場所と手法は非常に可変です。
Blazor は、包括的で意見の豊富な状態管理を提供しません。 Flux、Redux、MobX など、 Blazorとシームレスに連携するサードパーティの状態コンテナー製品とサービスは、事実上すべてのアプリ要件を満たします。
この記事の残りの部分では、あらゆる種類の Blazor アプリの一般的な状態管理戦略について説明します。
URL を使用した状態管理
ナビゲーションの状態を表わす一時的なデータについては、URL の一部としてデータをモデル化します。 たとえば、次のようなユーザー状態が URL でモデル化されます。
- 表示されるエンティティの ID。
- ページ付きグリッドでの現在のページ番号。
次の場合、ブラウザーのアドレス バーのコンテンツが保持されます。
- ユーザーがページを手動で再読み込みした。
- サーバー側のシナリオのみ: Web サーバーが使用できなくなった場合、ユーザーは別のサーバーに接続するためにページの再読み込みを強制されます。
@page ディレクティブを使用して URL パターンを定義する方法については、「ASP.NET Core Blazor ルーティング」を参照してください。
メモリ内状態コンテナー サービス
入れ子になったコンポーネントは通常、「」で説明されているように、"チェーン バインド" を使用してデータをバインドします。Blazor 入れ子になったコンポーネントと入れ子になっていないコンポーネントでは、登録済みのメモリ内状態コンテナーを使用してデータへのアクセスを共有できます。 カスタムの状態コンテナー クラスでは、割り当て可能な Action を使用して、状態変更のアプリのさまざまな部分でコンポーネントに通知できます。 次に例を示します。
- コンポーネントのペアでは、状態コンテナーを使用してプロパティを追跡します。
- 次の例の 1 つのコンポーネントは、他のコンポーネントで入れ子になっていますが、この方法を使用するには入れ子である必要はありません。
Von Bedeutung
このセクションの例では、メモリ内状態コンテナー サービスを作成し、サービスを登録し、コンポーネントでサービスを使用する方法を示します。 この例では、それ以上開発しないとデータは保持されません。 データの永続ストレージの場合、状態コンテナーは、ブラウザー メモリがクリアされたときに存続する基になるストレージ メカニズムを採用する必要があります。 これは、localStorage/sessionStorage またはその他のテクノロジを使用して実現できます。
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();
}
クライアント側アプリ (Program ファイル):
builder.Services.AddSingleton<StateContainer>();
サーバー側アプリ (Program ファイル、.NET 6.0 以降の ASP.NET Core):
builder.Services.AddScoped<StateContainer>();
サーバー側アプリケーション (Startup.ConfigureServicesのStartup.cs、通常は .NET 6 以前):
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;
}
}
前のコンポーネントによって IDisposable が実装され、OnChange メソッドで Dispose デリゲートがサブスクライブ解除されます。このメソッドは、コンポーネントが破棄されるときにフレームワークによって呼び出されます。 詳細については、ASP.NET Core Razor コンポーネントの破棄を参照してください。
値とパラメーターの連続性
カスケード値とパラメーターを使用して、先祖Razorコンポーネントから子孫コンポーネントにデータをフローすることで状態を管理します。
- 多くのコンポーネントで状態を使用する。
- 最上位の状態オブジェクトを 1 つだけ保持する場合。
CascadingValueSource<TValue>を持つルートレベルのカスケード値によって、変更されたカスケード値を受信するコンポーネントサブスクライバーは通知を許可されます。 詳細と実際の例については、ASP.NET Core NotifyingDalekカスケード値とパラメーターのBlazorの例を参照してください。
Blazorの同期コンテキストの外部からの状態変更をサポートする
外部からの状態変更をサポートしたい場合(例えば、タイマーやバックグラウンドサービスから)に、Blazorの同期コンテキスト外でカスタム状態管理サービスを使用するときは、すべてのコンポーネントが StateHasChanged の呼び出しを ComponentBase.InvokeAsyncでラップする必要があります。 これにより、レンダラーの同期コンテキストで変更通知が処理されます。
状態管理サービスが StateHasChanged の同期コンテキストで Blazor を呼び出さない場合は、次のエラーがスローされます。
System.InvalidOperationException: "現在のスレッドは Dispatcher に関連付けられていません。 レンダリングまたはコンポーネントの状態をトリガーするとき、InvokeAsync() を使用して Dispatcher に実行を切り替えます"
このエラーに対処する方法の詳しい情報と例については、「ASP.NET Core Razor コンポーネントのレンダリング」をご覧ください。
ASP.NET Core