Blazor dari Nol: Bab 3 — Komponen yang Skalabel
Selamat datang di Bab 3 Blazor dari Nol. Kalau kamu belum membaca Bab 2, baca dulu agar proyek dasar kamu sudah siap.
Di Bab 2 kita membuat aplikasi berjalan. Di bab ini kita membuatnya mudah dipelihara.
Proyek Blazor cepat berantakan kalau setiap halaman jadi file .razor yang besar. Komponen membantu mencegah itu: konsistensi, reuse, dan batas yang jelas antar bagian UI.
Sebenarnya apa itu komponen Blazor?
Komponen adalah file .razor yang bisa:
- Merender markup
- Menyimpan state lokal
- Menerima input lewat parameter
- Mengirim event ke komponen parent
- Merender konten child
Saat runtime, Blazor memperlakukan komponen sebagai mesin state kecil. Saat state berubah, Blazor re-render dan menerapkan diff DOM.
Jadi targetmu adalah input yang jelas dan perilaku yang bisa diprediksi.
Langkah 1: Mulai dari komponen yang fokus
Buat 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; }
}
Pakai di Components/Pages/Home.razor:
@page "/"
<PageTitle>Blazor dari Nol</PageTitle>
<SectionHeader
Title="Blazor dari Nol"
Subtitle="Bab 3 membahas komponen." />
Contoh ini kecil, tapi idenya besar: komponen seharusnya mudah dipahami hanya dari parameternya.
Langkah 2: Gunakan parameter untuk perilaku yang eksplisit
Sekarang kita buat tombol reusable.
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"
};
}
Pemakaian:
@code {
private int _savedCount;
private void Save()
{
_savedCount++;
}
}
<AppButton Text="Save" Variant="primary" OnClick="Save" />
<p>Tersimpan @_savedCount kali.</p>
Fokus utamanya adalah desain kontrak:
- Parameter sedikit dan jelas
- Nama eksplisit, bukan perilaku “ajaib”
- Default yang aman
Langkah 3: Pakai RenderFragment untuk komposisi layout
RenderFragment memungkinkan parent mengirim blok UI ke child.
Buat 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; }
}
Pemakaian:
<Card Title="Roadmap">
<ul>
<li>Komponen</li>
<li>Data binding</li>
<li>Routing</li>
</ul>
</Card>
Pola ini menjaga struktur halaman tetap konsisten tanpa mengulang wrapper markup.
Langkah 4: Utamakan komposisi dibanding halaman raksasa
Kalau halaman makin besar, pecah berdasarkan tanggung jawab:
ProfileSummaryuntuk blok identitasProfileStatsuntuk metrikProfileActivityListuntuk aktivitas terbaru
Dengan begitu halaman jadi orchestration layer, bukan tempat semua detail dicampur.
Langkah 5: Seimbangkan markup dan logic
Untuk komponen sederhana, inline @code sudah cukup.
Untuk komponen besar, pindahkan logic ke code-behind:
UserCard.razorUserCard.razor.cs
Ini membuat markup dan logic C# sama-sama lebih mudah dibaca.
Langkah 6: Struktur folder yang praktis
Struktur yang biasanya nyaman untuk scaling:
Components/Pages/-> halaman yang punya routeComponents/Layout/-> app shell dan navigasiComponents/Common/-> building block generik bersamaComponents/Features/<FeatureName>/-> komponen khusus fitur
Kesalahan umum di proyek Blazor awal
- Terlalu banyak parameter daripada memakai view model khusus
- Menaruh business rules langsung di page component
- Membuat satu “God component” ratusan baris
- Mengulang pola markup alih-alih ekstraksi komponen kecil
Bab berikutnya
Di Bab 4 kita fokus ke data binding dan events: @bind, event handling, trade-off two-way binding, dan pola state yang tetap predictable.