.NET Core 3.0 – Criando componentes no Razor Components

Em um artigo passado, falei sobre o Razor Components. Este novo tipo de aplicação, presente no .NET Core 3.0. Como dito anteriormente, o Razor Components é uma evolução do Blazor. Uma forma de criar componentes web no C#. Uma analogia seria com os componentes de frameworks JavaScript, como React e Angular.

Assim como nesses frameworks, os componentes do Razor encapsulam toda a lógica. Podendo ser adicionados em qualquer aplicação ASP.NET.

C# (C Sharp) Básico
Curso de C# (C Sharp) Básico
CONHEÇA O CURSO

Para compreender isso, vamos colocar a mão na massa.

Este artigo está sendo escrito com base nas definições do NET Core 3 Preview 3, então no futuro algumas informações não podem ser compatíveis com a versão mais atual do .NET Core. E os exemplos demostrados aqui, requerem esta versão do framework ou uma superior.

Estrutura de um componente Razor

Pelo terminal, é possível criar uma aplicação Razor Components com o comando abaixo:

dotnet new razorcomponents -n RazorApp

Na aplicação criada, você notará uma pasta chamada Components e dentro dela localizará arquivos com a extensão *.razor:

Esses arquivos são os componentes do Razor. Ao verificar o código de um componente, teremos:

@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

@functions {
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;
    }
}

O início (@page "/counter") define a URL do componente. Dentro dela há códigos HTML e um bloco com a anotação @functions:

@functions {
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;
    }
}

Como o nome indica, no bloco desta anotação são definidas funções invocadas pelos componentes. Elas podem ser referenciadas no HTML do arquivo através da arroba (@) como no trecho abaixo:

<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

Qualquer código definido neste ponto pode ser referenciado no HTML com a arroba, como é o caso da variável currentCount:

<p>Current count: @currentCount</p>

Ao executar a aplicação (dotnet run), podemos acessar o componente em /counter e visualizar o seu comportamento:

Criando um componente/página Razor

Agora que conhecemos um pouco da estrutura de um componente Razor vamos criar o nosso. Este primeiro componente será uma página, então dentro da pasta Components/Pages, adicione um arquivo chamado Posts.razor e nele adicione o código abaixo:

@page "/posts"
@using RazorApp.Services
@inject BlogService blogService

<h1>Posts</h1>

@if (posts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    @foreach (var post in posts)
    {
        <div class="card" style="width: 36rem;">
            <div class="card-body">
                <h1 class="card-title">@post.Title</h1>
                <p class="card-text">@post.Content</p>
            </div>
        </div>
    }
}

@functions {
    Post[] posts;

    protected override async Task OnInitAsync()
    {
        posts = await blogService.GetPostsAsync();
    }
}

Note que nesta página estamos definindo a listagem de posts:

@foreach (var post in posts)
{
    <div class="card" style="width: 36rem;">
        <div class="card-body">
            <h1 class="card-title">@post.Title</h1>
            <p class="card-text">@post.Content</p>
        </div>
    </div>
}

Dados que virão de um service (BlogService), chamado na criação da página:

protected override async Task OnInitAsync()
{
    posts = await blogService.GetPostsAsync();
}

Assim, é necessário definir este service:

namespace RazorApp.Services
{
    public class BlogService 
    {
        public Task<Post[]> GetPostsAsync()
        {
            return Task.FromResult<Post[]>(new Post[]
            {
                new Post { Title = "Post 1", Content = "Conteúdo do Post 1" },
                new Post { Title = "Post 2", Content = "Conteúdo do Post 2" },
                new Post { Title = "Post 3", Content = "Conteúdo do Post 3" },
                new Post { Title = "Post 4", Content = "Conteúdo do Post 4" }
            });
        }
    }
}

Que contém apenas dados de exemplo. Em uma aplicação real, esta informação poderia vir do banco e/ou uma API.

C# (C Sharp) Intermediário
Curso de C# (C Sharp) Intermediário
CONHEÇA O CURSO

Também será necessário definir o model Post:

public class Post 
{
    public string Title { get; set; }
    public string Content { get; set; }
}

“Injetar” o service na classe Startup:

public void ConfigureServices(IServiceCollection services)
{
    //Código omitido

    services.AddSingleton<BlogService>();
}

Por fim, no arquivo NavMenu.razor (presente na pasta Components/Shared), adicione um link para a página que acabamos de definir:

<li class="nav-item px-3">
    <NavLink class="nav-link" href="posts">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Posts
    </NavLink>
</li>

Ao acessar a aplicação, teremos acesso a esta página:

Simples, não é?

Criando um componente reutilizável

Agora que vimos como criar uma página, veremos como criar um componente reutilizável, que poderá ser adicionado em outras páginas e/ou componentes da aplicação.

Assim como o anterior, este componente será criado dentro da pasta Components/Pages, agora com o nome de LikeButton.razor e nele adicione o código abaixo:

<button onclick="@Liked" 
        class="btn @( likedCount == 0 ? "btn-outline-secondary" : "btn-outline-danger" )">
    <i class="far fa-heart"></i>
    @likedCount
</button>

@functions {
    [Parameter] int InitialLikedCount { get; set; }

    int likedCount = 0;

    protected override void OnInit()
    {
        likedCount = InitialLikedCount;
    }

    void Liked()
    {
        likedCount++;
    }
}

Neste componente estamos definindo um botão:

<button onclick="@Liked" 
        class="btn @( likedCount == 0 ? "btn-outline-secondary" : "btn-outline-danger" )">
    <i class="far fa-heart"></i>
    @likedCount
</button>

Este botão contém o ícone de coração do font-awesome, então é necessário adicionar a referência dela na página Index.cshml (localizada em Pages). No bloco @functions, é definido um parâmetro:

[Parameter] int InitialLikedCount { get; set; }

Que será atribuído a variável likedCount na inicialização da página:

protected override void OnInit()
{
    likedCount = InitialLikedCount;
}

Como é possível notar, ao definir [Parameter] , indicamos que o valor da variável irá como um atributo do componente.

Já no método Liked a variável likedCount é incrementada:

void Liked()
{
    likedCount++;
}

Para utilizar este componente, basta defini-lo em outra página como uma tag:

<LikedButton>

Faça isso no componente que criamos anteriormente:

@foreach (var post in posts)
{
    <div class="card" style="width: 36rem;">
        <div class="card-body">
            <h1 class="card-title">@post.Title</h1>
            <p class="card-text">@post.Content</p>
        </div>
        <div class="card-footer">
            <LikeButton />
        </div>
    </div>
}

Inicialmente não estamos passando o parâmetro para o componente, mesmo assim ele funciona:

Caso seja passado o parâmetro:

@foreach (var post in posts)
{
    <div class="card" style="width: 36rem;">
        <div class="card-body">
            <h1 class="card-title">@post.Title</h1>
            <p class="card-text">@post.Content</p>
        </div>
        <div class="card-footer">
            <LikeButton InitialLikedCount="5" />
        </div>
    </div>
}

O componente será inicializado com o valor informado:

C# (C Sharp) Avançado
Curso de C# (C Sharp) Avançado
CONHEÇA O CURSO

Conclusão

Este é um exemplo simples de criação e reutilização de componentes, mas nele é possível notar o poder deste recurso. Tenho certeza que não irá demorar muito para termos componentes para ecossistemas específicos, como Bootstrap, Material, etc.

Deixe seu comentário

Instrutor, nerd, cinéfilo e desenvolvedor nas horas vagas. Graduado em Ciências da Computação pela Universidade Metodista de São Paulo.