Compartilhar dados em aplicativos Blazor

Concluído

O Blazor inclui várias maneiras de compartilhar informações entre componentes. Você pode usar parâmetros de componente ou parâmetros em cascata para enviar valores de um componente pai para um componente filho. O padrão AppState é outra abordagem possível para armazenar valores e acessá-los de qualquer componente no aplicativo.

Suponha que você esteja trabalhando no novo site de entrega de pizza. Várias pizzas devem ser exibidas da mesma maneira na página inicial. Você deseja exibir as pizzas renderizando um componente filho para cada pizza. Agora, você quer passar uma ID para esse componente filho que determina a pizza que será exibida. Você também quer armazenar e exibir um valor em vários componentes que mostra o número total de pizzas que você vendeu hoje.

Nesta unidade, você aprenderá três técnicas diferentes que podem ser usadas para compartilhar valores entre dois ou mais componentes Blazor.

Como compartilhar informações com outros componentes usando parâmetros de componentes

Em um aplicativo Web Blazor, cada componente renderiza uma parte do HTML. Alguns componentes renderizam uma página completa, mas outros renderizam fragmentos menores de marcação, tais como uma tabela, um formulário ou um único controle. Se o seu componente renderizar apenas uma seção de marcação, use-o como um componente filho dentro de um componente pai. Seu componente filho também pode ser pai de outros componentes menores que são renderizados dentro dele. Os componentes filho também são conhecidos como componentes aninhados.

Nessa hierarquia de componentes pai e filho, é possível compartilhar informações entre eles usando parâmetros de componente. Defina os parâmetros em componentes filho e defina seus valores no pai. Por exemplo, se você tiver um componente filho que exiba fotos de pizza, poderá usar um parâmetro de componente para passar a ID da pizza. O componente filho pesquisa a pizza a partir da ID e obtém imagens e outros dados. Se você quiser exibir várias pizzas diferentes, poderá usar esse componente filho várias vezes na mesma página pai, passando uma ID diferente para cada filho.

Comece definindo o parâmetro de componente no componente filho. Ele é definido como uma propriedade pública C# e decorado com o atributo [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."
}

Como os parâmetros do componente são membros do componente filho, é possível renderizá-los em seu HTML usando o símbolo @ reservado do Blazor, seguido de seu nome. Além disso, o código anterior especifica um valor padrão para o parâmetro PizzaDescription. Esse valor é renderizado se o componente pai não transmite um valor. Caso contrário, ele é substituído pelo valor transmitido pelo pai.

Você também pode usar classes personalizadas em seu projeto como parâmetros de componente. Considere esta classe que descreve um recheio:

public class PizzaTopping
{
    public string Name { get; set; }
    public string Ingredients { get; set; }
}

Você pode usá-la como um parâmetro de componente da mesma maneira que um valor de parâmetro, para acessar propriedades individuais da classe usando a sintaxe de ponto:

<h2>New Topping: @Topping.Name</h2>

<p>Ingredients: @Topping.Ingredients</p>

@code {
    [Parameter]
    public PizzaTopping Topping { get; set; }
}

No componente pai, defina os valores de parâmetro usando atributos das tags do componente filho. Você define componentes simples diretamente. Com um parâmetro baseado em uma classe personalizada, use o código C# embutido para criar uma nova instância dessa classe e definir seus valores:

@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." })" />

Compartilhar informações usando parâmetros em cascata

Os parâmetros de componente funcionam bem quando você quer passar um valor para o filho imediato de um componente. As coisas se complicam quando você tem uma hierarquia profunda com filhos de filhos e assim por diante. Os parâmetros do componente não são transmitidos automaticamente para os componentes neto a partir dos componentes ancestrais ou mais para baixo na hierarquia. Para lidar com esse problema de forma elegante, o Blazor inclui parâmetros em cascata. Quando você define o valor de um parâmetro em cascata em um componente, seu valor fica automaticamente disponível a todos os componentes descendentes, em qualquer profundidade.

No componente pai, o uso da tag <CascadingValue> especifica as informações que serão transmitidas em cascata para todos os descendentes. Essa tag é implementada como um componente Blazor integrado. Qualquer componente renderizado dentro dessa marca pode acessar o valor.

@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>

Nos componentes descendentes, é possível acessar o valor em cascata usando membros de componentes e decorando-os com o atributo [CascadingParameter].

<h2>Deal: @DealName</h2>

@code {
    [CascadingParameter(Name="DealName")]
    private string DealName { get; set; }
}

Assim, neste exemplo, a tag <h2> tem o conteúdo Deal: Throwback Thursday, pois esse valor em cascata foi definido por um componente ancestral.

Observação

Com relação aos parâmetros de componente, será possível passar objetos como parâmetros em cascata se você tiver requisitos mais complexos.

No exemplo anterior, o valor em cascata é identificado pelo atributo Name no pai, que corresponde ao valor Name no atributo [CascadingParameter]. Opcionalmente, você pode omitir esses nomes. Nesse caso, os atributos são correspondidos por tipo. Omitir o nome funciona bem quando você tem apenas um parâmetro desse tipo. Se você quiser passar em cascata dois valores de cadeia de caracteres diferentes, deverá usar nomes de parâmetro para evitar qualquer ambiguidade.

Compartilhar informações usando AppState

Outra abordagem para compartilhar informações entre componentes diferentes é usar o padrão AppState. Você cria uma classe que define as propriedades que deseja armazenar e a registra como um serviço com escopo. Em qualquer componente em que você deseja definir ou usar os valores de AppState, injete o serviço e, em seguida, poderá acessar suas propriedades. Ao contrário dos parâmetros de componente e dos parâmetros em cascata, os valores em AppState estão disponíveis para todos os componentes no aplicativo, até mesmo os componentes que não são filhos do componente que armazenou o valor.

Como exemplo, considere esta classe que armazena um valor sobre vendas:

public class PizzaSalesState
{
    public int PizzasSoldToday { get; set; }
}

Você adicionará a classe como um serviço com escopo ao arquivo Program.cs:

...
// Add services to the container
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

// Add the AppState class
builder.Services.AddScoped<PizzaSalesState>();
...

Agora, em qualquer componente em que você queira definir ou recuperar valores de AppState, você pode injetar a classe e acessar as propriedades:

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

Observação

Esse código implementa um contador que é incrementado quando o usuário seleciona um botão, muito parecido com o exemplo no Tutorial do Blazor – Criar seu primeiro aplicativo Blazor. A diferença é que, nesse caso, como armazenamos o valor do contador em um serviço com escopo AppState, a contagem persiste entre carregamentos de página e pode ser vista por outros usuários.

Na próxima unidade, você mesmo tentará fazer isso!