Blazor アプリケーションでデータを共有する
Blazor には、コンポーネント間で情報を共有するいくつかの方法が含まれています。 コンポーネント パラメーターまたはカスケード型パラメーターを使用して、親コンポーネントから子コンポーネントに値を送信できます。 AppState パターンは、値を格納し、アプリケーションの任意のコンポーネントからそれらにアクセスするために使用できるもう 1 つのアプローチです。
新しい宅配ピザ Web サイトに取り組んでいるとします。 ホーム ページには、同じように複数のピザを表示する必要があります。 あなたは、各ピザに子コンポーネントをレンダリングして、ピザを表示しようと考えます。 ここで、表示するピザを指定する ID をその子コンポーネントに渡したいと考えます。 さらに、複数のコンポーネントで、今日販売したピザの総数を示す値を格納して表示したいと考えます。
このユニットでは、複数の Blazor コンポーネント間で値を共有するために使用できる 3 つの異なる手法について説明します。
コンポーネント パラメーターを使用して他のコンポーネントと情報を共有する
Blazor Web アプリでは、各コンポーネントによって HTML の一部がレンダリングされます。 完全なページをレンダリングするコンポーネントもありますが、テーブル、フォーム、1 つのコントロールなど、マークアップの小さなフラグメントをレンダリングするコンポーネントもあります。 コンポーネントで、マークアップの 1 つのセクションのみをレンダリングする場合、親コンポーネント内の子コンポーネントとしてそれを使用する必要があります。 子コンポーネントは、その中にレンダリングされる他のさらに小さなコンポーネントの親になることもできます。 子コンポーネントは、入れ子になったコンポーネントとも呼ばれます。
親コンポーネントと子コンポーネントのこの階層では、コンポーネント パラメーターを使用して、それらの間で情報を共有できます。 これらのパラメーターを子コンポーネントに定義し、親にそれらの値を設定します。 たとえば、ピザの写真を表示する子コンポーネントがある場合、コンポーネント パラメーターを使用して、ピザ ID を渡すことができます。 子コンポーネントでは、ID からピザを検索し、画像や他のデータを取得します。 多数のさまざまなピザを表示する場合は、同じ親ページでこの子コンポーネントを複数回使用して、各子に異なる ID を渡します。
最初に、子コンポーネントにコンポーネント パラメーターを定義します。 それを C# パブリック プロパティとして定義し、[Parameter]
属性で装飾します。
<h2>New Pizza: @PizzaName</h2>
<p>@PizzaDescription</p>
@code {
[Parameter]
public string PizzaName { get; set; }
[Parameter]
public string PizzaDescription { get; set; } = "The best pizza you've ever tasted."
}
コンポーネント パラメーターは子コンポーネントのメンバーであるため、Blazor の予約済みの @
記号とそれに続く名前を使用して HTML にそれらをレンダリングできます。 さらに、前記のコードでは、PizzaDescription
パラメーターの既定値を指定しています。 この値は、親コンポーネントが値を渡さない場合にレンダリングされます。 それ以外の場合は、親から渡された値によってオーバーライドされます。
プロジェクトで、カスタム クラスをコンポーネント パラメーターとして使用することもできます。 トッピングを記述する次のクラスについて考えます。
public class PizzaTopping
{
public string Name { get; set; }
public string Ingredients { get; set; }
}
それをパラメーター値と同じようにコンポーネント パラメーターとして使用し、ドット構文を使用してクラスの個々のプロパティにアクセスできます。
<h2>New Topping: @Topping.Name</h2>
<p>Ingredients: @Topping.Ingredients</p>
@code {
[Parameter]
public PizzaTopping Topping { get; set; }
}
親コンポーネントで、子コンポーネントのタグの属性を使用してパラメーター値を設定します。 単純なコンポーネントを直接設定します。 カスタム クラスに基づいたパラメーターで、インライン C# コードを使用して、そのクラスの新しいインスタンスを作成し、その値を設定します。
@page "/pizzas-toppings"
<h1>Our Latest Pizzas and Topping</h1>
<Pizza PizzaName="Hawaiian" PizzaDescription="The one with pineapple" />
<PizzaTopping Topping="@(new PizzaTopping() { Name = "Chilli Sauce", Ingredients = "Three kinds of chilli." })" />
カスケード型パラメーターを使用して情報を共有する
コンポーネント パラメーターは、コンポーネントの直接の子に値を渡す場合にうまく機能します。 子の子などのように深い階層がある場合は、扱いにくくなります。 コンポーネント パラメーターは、先祖コンポーネントから孫コンポーネントに、または階層のさらに下に自動的に渡されることはありません。 この問題を適切に処理するために、Blazor にはカスケード型パラメーターが含まれています。 コンポーネントにカスケード型パラメーターの値を設定すると、その値は、任意の深さのすべての子孫コンポーネントから自動的に使用できます。
親コンポーネントで、<CascadingValue>
タグを使用して、すべての子孫に連鎖する情報を指定します。 このタグは、組み込みの Blazor コンポーネントとして実装されます。 そのタグ内でレンダリングされるすべてのコンポーネントが、値にアクセスできます。
@page "/specialoffers"
<h1>Special Offers</h1>
<CascadingValue Name="DealName" Value="Throwback Thursday">
<!-- Any descendant component rendered here will be able to access the cascading value. -->
</CascadingValue>
子孫コンポーネントで、カスケード値にアクセスするには、コンポーネント メンバーを使用し、それらを [CascadingParameter]
属性で装飾します。
<h2>Deal: @DealName</h2>
@code {
[CascadingParameter(Name="DealName")]
private string DealName { get; set; }
}
そのため、この例では、<h2>
タグの内容は Deal: Throwback Thursday
になります。そのカスケード値が先祖コンポーネントによって設定されたためです。
注意
コンポーネント パラメーターに関しては、より複雑な要件がある場合に、カスケード型パラメーターとしてオブジェクトを渡すことができます。
前の例では、カスケード値が親の Name
属性によって識別され、[CascadingParameter]
属性のName
値に対して照合されます。 必要に応じて、これらの名前を省略できます。その場合、属性は型によって照合されます。 名前の省略は、その型のパラメーターが 1 つしかない場合にうまく機能します。 2 つの異なる文字列値を連鎖させる場合は、あいまいさを避けるためにパラメーター名を使用する必要があります。
AppState を使用して情報を共有する
さまざまなコンポーネント間で情報を共有するもう 1 つの方法は、AppState パターンを使用することです。 格納するプロパティを定義するクラスを作成し、それをスコープ付きサービスとして登録します。 AppState 値を設定または使用するすべてのコンポーネントで、サービスを挿入すると、そのプロパティにアクセスできます。 コンポーネント パラメーターやカスケード型パラメーターとは異なり、AppState の値は、アプリケーションのすべてのコンポーネント (値を格納したコンポーネントの子ではないコンポーネントでも) から使用できます。
例として、売上に関する値を格納するこのクラスについて考えます。
public class PizzaSalesState
{
public int PizzasSoldToday { get; set; }
}
Program.cs ファイルにスコープ付きサービスとしてクラスを追加します。
...
// Add services to the container
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
// Add the AppState class
builder.Services.AddScoped<PizzaSalesState>();
...
これで、AppState の値を設定または取得する任意のコンポーネントにおいて、クラスを挿入してから、プロパティにアクセスすることができます。
@page "/"
@inject PizzaSalesState SalesState
<h1>Welcome to Blazing Pizzas</h1>
<p>Today, we've sold this many pizzas: @SalesState.PizzasSoldToday</p>
<button @onclick="IncrementSales">Buy a Pizza</button>
@code {
private void IncrementSales()
{
SalesState.PizzasSoldToday++;
}
}
注意
このコードでは、ユーザーがボタンを選ぶと増分するカウンターを実装します。「Blazor チュートリアル - 最初の Blazor アプリをビルドする」の例によく似ています。 違いは、この例では、カウンターの値を AppState スコープ付きサービスに格納しているため、ページの読み込み間でカウントが保持され、他のユーザーが表示できることです。
次のユニットでは、自分で試してみましょう。