Blazor do zero: Capítulo 3 — Componentes que escalam

· 3 min de leitura

Bem-vindo ao Capítulo 3 de Blazor do zero. Se você não leu o Capítulo 2, leia primeiro para já ter o projeto base pronto.

No Capítulo 2 fizemos a aplicação rodar. Neste capítulo vamos deixá-la sustentável.

Projetos Blazor ficam bagunçados rápido quando cada página vira um .razor gigante. Componentes são a forma de evitar isso: trazem consistência, reutilização e limites claros entre partes da interface.


O que um componente Blazor realmente é

Um componente é um arquivo .razor que pode:

  • Renderizar markup
  • Manter estado local
  • Receber dados via parâmetros
  • Emitir eventos para o componente pai
  • Renderizar conteúdo filho

Em execução, o Blazor trata cada componente como uma pequena máquina de estado. Quando o estado muda, ele renderiza novamente e aplica um diff no DOM.

Por isso você deve desenhar entradas limpas e comportamento previsível.


Passo 1: Comece com um componente focado

Crie Components/Common/SectionHeader.razor:

<header class="section-header">
    <h2>@Title</h2>
    @if (!string.IsNullOrWhiteSpace(Subtitle))
    {
        <p>@Subtitle</p>
    }
</header>

@code {
    [Parameter] public string Title { get; set; } = string.Empty;
    [Parameter] public string? Subtitle { get; set; }
}

Use em Components/Pages/Home.razor:

@page "/"

<PageTitle>Blazor do zero</PageTitle>

<SectionHeader
    Title="Blazor do zero"
    Subtitle="O capítulo 3 é sobre componentes." />

É um exemplo simples, mas introduz a ideia central: os parâmetros devem explicar o componente.


Passo 2: Use parâmetros para deixar o comportamento explícito

Vamos criar um botão reutilizável.

Components/Common/AppButton.razor:

<button class="app-button @VariantCssClass" @onclick="OnClick">
    @Text
</button>

@code {
    [Parameter] public string Text { get; set; } = "Button";
    [Parameter] public string Variant { get; set; } = "primary";
    [Parameter] public EventCallback OnClick { get; set; }

    private string VariantCssClass => Variant.ToLowerInvariant() switch
    {
        "secondary" => "app-button--secondary",
        "danger" => "app-button--danger",
        _ => "app-button--primary"
    };
}

Uso:

@code {
    private int _savedCount;

    private void Save()
    {
        _savedCount++;
    }
}

<AppButton Text="Save" Variant="primary" OnClick="Save" />
<p>Salvo @_savedCount vezes.</p>

O ponto principal é o contrato:

  • Parâmetros pequenos e claros
  • Nomes explícitos, sem comportamento “mágico”
  • Defaults seguros

Passo 3: Use RenderFragment para composição

RenderFragment permite que o componente pai injete blocos de UI no filho.

Crie Components/Common/Card.razor:

<article class="card">
    <header class="card__header">@Title</header>
    <section class="card__body">
        @ChildContent
    </section>
</article>

@code {
    [Parameter] public string Title { get; set; } = string.Empty;
    [Parameter] public RenderFragment? ChildContent { get; set; }
}

Uso:

<Card Title="Roadmap">
    <ul>
        <li>Componentes</li>
        <li>Data binding</li>
        <li>Routing</li>
    </ul>
</Card>

Esse padrão evita repetir o mesmo markup de estrutura em várias páginas.


Passo 4: Prefira composição em vez de páginas gigantes

Se a página crescer demais, separe por responsabilidade:

  • ProfileSummary para o bloco principal
  • ProfileStats para métricas
  • ProfileActivityList para atividades recentes

Assim a página vira orquestração e não um bloco monolítico.


Passo 5: Equilibre markup e lógica

Para componentes simples, @code inline funciona bem.

Para componentes maiores, mova lógica para code-behind:

  • UserCard.razor
  • UserCard.razor.cs

Isso melhora a leitura do markup e da lógica C#.


Passo 6: Estrutura de pastas prática

Uma organização que costuma escalar bem:

  • Components/Pages/ -> páginas roteáveis
  • Components/Layout/ -> shell e navegação
  • Components/Common/ -> blocos genéricos compartilhados
  • Components/Features/<FeatureName>/ -> componentes de cada feature

Erros comuns no início com Blazor

  • Passar parâmetros demais em vez de usar um view model dedicado
  • Colocar regra de negócio dentro de componentes de página
  • Criar um “componente Deus” com centenas de linhas
  • Repetir padrões de markup em vez de extrair peças reutilizáveis

Próximo capítulo

No Capítulo 4 vamos focar em data binding e eventos: @bind, tratamento de eventos, tradeoffs do two-way binding e padrões para manter estado previsível.