導入
「ログイン中のユーザー」「カートの中身」のように、複数のコンポーネントで共有したい状態は、パラメータのバケツリレーでは大変です。共有状態をサービスにまとめ、DIで各コンポーネントに配り、変化をeventで通知するのが定番です。
説明
状態を持つサービスを作り、変化時にイベントを発火します。各コンポーネントは@injectで受け取り、そのイベントを購読して再描画します。
// 共有する状態をサービスに(Program.cs で AddSingleton<CartService>())
public class CartService
{
private readonly List<string> _items = new();
public IReadOnlyList<string> Items => _items;
public event Action? OnChange; // 変化を購読者に通知するイベント
public void Add(string item)
{
_items.Add(item);
OnChange?.Invoke(); // 全購読者に「変わった」と知らせる
}
}
@inject CartService Cart
@implements IDisposable
<p>カート: @Cart.Items.Count 個</p>
<button @onclick='() => Cart.Add("商品A")'>追加</button>
@code {
protected override void OnInitialized() => Cart.OnChange += StateHasChanged;
public void Dispose() => Cart.OnChange -= StateHasChanged;
}
flowchart TB
S["CartService(状態+OnChange)<br/>AddSingleton で1つ"] --> C1["ヘッダー(個数表示)"]
S --> C2["商品一覧(追加ボタン)"]
S --> C3["カートページ(中身)"]
- 共有状態はサービスクラスにまとめ、
AddSingletonで1つ登録する - 変化は
event Action OnChangeで通知し、各コンポーネントはOnChange += StateHasChangedで再描画 - 購読したら
IDisposableのDisposeで必ず解除する(メモリリーク防止) - これはObserverパターンそのもの。学んだ設計原則が実アプリで統合される
まとめ
- 共有状態はサービス化してDIで配る
- 変化は
eventで通知し、StateHasChangedで再描画 - 購読解除(
IDisposable)を忘れない
次回: どうしてもJavaScriptが必要なときの相互運用です。