Sıfırdan Blazor: Bölüm 3 — Ölçeklenebilir Bileşenler

· 3 dk okuma

Sıfırdan Blazor serisinin 3. bölümüne hoş geldin. Bölüm 2‘yi kaçırdıysan önce onu oku; temel proje hazır olsun.

Bölüm 2’de uygulamayı çalıştırdık. Bu bölümde onu bakımı kolay hale getireceğiz.

Blazor projeleri, her sayfa dev bir .razor dosyasına dönüştüğünde hızlıca karmaşıklaşır. Bileşenler bunu engeller: tutarlılık, tekrar kullanım ve UI parçaları arasında net sınırlar sağlar.


Blazor bileşeni aslında nedir?

Bileşen, şunları yapabilen bir .razor dosyasıdır:

  • Markup render etmek
  • Yerel durum (state) tutmak
  • Parametrelerle girdi almak
  • Üst bileşene olay (event) göndermek
  • Çocuk içerik render etmek

Çalışma anında Blazor her bileşeni küçük bir durum makinesi gibi ele alır. Durum değiştiğinde yeniden render eder ve DOM farkını uygular.

Bu yüzden hedefin temiz girdiler ve öngörülebilir davranış olmalı.


Adım 1: Odaklı bir bileşenle başla

Components/Common/SectionHeader.razor oluştur:

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

Components/Pages/Home.razor içinde kullan:

@page "/"

<PageTitle>Sıfırdan Blazor</PageTitle>

<SectionHeader
    Title="Sıfırdan Blazor"
    Subtitle="3. bölüm bileşenler hakkında." />

Küçük bir örnek ama ana fikir net: bir bileşen sadece parametrelerine bakılarak anlaşılabilmeli.


Adım 2: Davranışı parametrelerle açık hale getir

Yeniden kullanılabilir bir buton oluşturalım.

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"
    };
}

Kullanım:

@code {
    private int _savedCount;

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

<AppButton Text="Save" Variant="primary" OnClick="Save" />
<p>@_savedCount kez kaydedildi.</p>

Buradaki asıl nokta sözleşme tasarımıdır:

  • Az ve net parametreler
  • Gizli davranış yerine açık isimler
  • Güvenli varsayılan değerler

Adım 3: Düzen kompozisyonu için RenderFragment

RenderFragment, üst bileşenin alt bileşene UI blokları göndermesini sağlar.

Components/Common/Card.razor oluştur:

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

Kullanım:

<Card Title="Roadmap">
    <ul>
        <li>Bileşenler</li>
        <li>Data binding</li>
        <li>Routing</li>
    </ul>
</Card>

Bu yaklaşım, aynı kapsayıcı markup’ı tekrar etmeden tutarlı sayfa yapısı kurmanı sağlar.


Adım 4: Dev sayfalar yerine kompozisyonu tercih et

Sayfa büyüdükçe sorumluluğa göre böl:

  • ProfileSummary üst profil bloğu
  • ProfileStats metrikler
  • ProfileActivityList son aktiviteler

Böylece sayfa, detayların yığıldığı yer değil, orkestrasyon katmanı olur.


Adım 5: Markup ve mantığı dengede tut

Basit bileşenlerde inline @code yeterlidir.

Büyük bileşenlerde code-behind kullan:

  • UserCard.razor
  • UserCard.razor.cs

Bu, hem markup’ı hem C# mantığını daha okunur yapar.


Adım 6: Pratik klasör yapısı

İyi ölçeklenen bir yapı:

  • Components/Pages/ -> route alabilen sayfalar
  • Components/Layout/ -> uygulama kabuğu ve navigasyon
  • Components/Common/ -> paylaşılan genel yapı taşları
  • Components/Features/<FeatureName>/ -> özellik odaklı bileşenler

Erken aşamada yapılan yaygın hatalar

  • Ayrı bir model yerine çok fazla parametre geçirmek
  • İş kurallarını sayfa bileşenlerine gömmek
  • Yüzlerce satırlık tek bir “tanrı bileşen” oluşturmak
  • Markup kalıplarını tekrar etmek yerine küçük bileşenlere ayırmamak

Sonraki bölüm

Bölüm 4’te data binding ve events konusuna geçiyoruz: @bind, olay yönetimi, two-way binding trade-off’ları ve state’i öngörülebilir tutan desenler.