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.
Curso C# (C Sharp) Básico
Conhecer o cursoPara 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.
Curso C# (C Sharp) Intermediário
Conhecer o cursoTambé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:
Curso C# (C Sharp) Avançado
Conhecer o cursoConclusã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.