Blazor à partir de zéro : Chapitre 3 — Des composants qui passent à l’échelle
Bienvenue dans le Chapitre 3 de Blazor à partir de zéro. Si vous avez manqué le Chapitre 2, commencez par là pour avoir le projet de base prêt.
Au Chapitre 2, on a fait tourner l’application. Ici, on la rend maintenable.
Les apps Blazor deviennent vite désordonnées quand chaque page finit en gros fichier .razor. Les composants évitent ça : plus de cohérence, plus de réutilisation, et des frontières claires entre les morceaux d’UI.
Ce qu’est vraiment un composant Blazor
Un composant est un fichier .razor qui peut :
- Rendre du markup
- Gérer un état local
- Recevoir des entrées via des paramètres
- Remonter des événements au parent
- Rendre du contenu enfant
À l’exécution, Blazor traite chaque composant comme une petite machine d’état. Quand l’état change, Blazor re-rend et applique un diff DOM.
Votre objectif : des entrées propres et un comportement prévisible.
Étape 1 : Commencer avec un composant ciblé
Créez 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; }
}
Utilisez-le dans Components/Pages/Home.razor :
@page "/"
<PageTitle>Blazor à partir de zéro</PageTitle>
<SectionHeader
Title="Blazor à partir de zéro"
Subtitle="Le chapitre 3 est consacré aux composants." />
Petit exemple, grande idée : un composant doit être lisible via ses paramètres.
Étape 2 : Utiliser les paramètres pour expliciter le comportement
Créons un bouton réutilisable.
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"
};
}
Utilisation :
@code {
private int _savedCount;
private void Save()
{
_savedCount++;
}
}
<AppButton Text="Save" Variant="primary" OnClick="Save" />
<p>Sauvegardé @_savedCount fois.</p>
Le point central est le contrat :
- Paramètres simples et clairs
- Noms explicites plutôt que logique implicite
- Valeurs par défaut sûres
Étape 3 : Utiliser RenderFragment pour la composition
RenderFragment permet au parent d’injecter des blocs d’UI dans l’enfant.
Créez 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; }
}
Utilisation :
<Card Title="Roadmap">
<ul>
<li>Composants</li>
<li>Data binding</li>
<li>Routing</li>
</ul>
</Card>
Ce pattern évite de répéter le même markup de structure partout.
Étape 4 : Préférer la composition aux pages géantes
Quand une page grossit trop, découpez par responsabilité :
ProfileSummarypour le bloc d’identitéProfileStatspour les métriquesProfileActivityListpour l’activité récente
La page devient orchestration, pas implémentation.
Étape 5 : Équilibrer markup et logique
Pour les composants simples, @code inline suffit.
Pour les composants plus gros, passez en code-behind :
UserCard.razorUserCard.razor.cs
Vous gagnez en lisibilité côté markup et côté logique C#.
Étape 6 : Une structure de dossiers pragmatique
Une structure qui passe bien à l’échelle :
Components/Pages/-> pages routablesComponents/Layout/-> shell applicatif et navigationComponents/Common/-> blocs génériques partagésComponents/Features/<FeatureName>/-> composants spécifiques à une feature
Erreurs fréquentes au début
- Trop de paramètres au lieu d’un modèle dédié
- Règles métier directement dans les pages
- Un composant “Dieu” de centaines de lignes
- Duplication de markup au lieu d’extraction de composants
Chapitre suivant
Dans le Chapitre 4, on abordera data binding et événements : @bind, gestion des événements, compromis du two-way binding et patterns pour garder un état prévisible.