Trudny / egzaminacyjny · lekcja 29
Komponenty Blazor — parametry, zdarzenia własne i cykl życia
Prawdziwa aplikacja nie mieści się w jednym komponencie — dzieli się na mniejsze, wielokrotnego użytku klocki (np. "karta produktu", "przycisk oceny gwiazdkami"), które przekazują sobie dane i informują się nawzajen o zdarzeniach. To dokładnie ta sama potrzeba...
Zacznij tutaj
Po co się tego uczymy?
Wprowadzenie
Teoria
Komponent potomny i parametry. Każdy plik .razor to jednocześnie DEFINICJA komponentu, którego można użyć wewnątrz INNEGO komponentu jak zwykłego znacznika HTML: <KartaProduktu Nazwa="Klawiatura" Cena="89.99" />. Żeby komponent KartaProduktu mógł PRZYJĄĆ takie dane, jego właściwości muszą być oznaczone atrybutem [Parameter] — to bezpośredni odpowiednik przekazywania danych do strony przez konstruktor w lekcji o nawigacji w dziale MAUI, tylko realizowany przez atrybuty znaczników HTML zamiast kodu C#.
Zdarzenia własne — komunikacja OD komponentu potomnego DO rodzica. Parametry przekazują dane W DÓŁ (rodzic → dziecko), ale co, gdy komponent potomny musi POINFORMOWAĆ rodzica o czymś (np. "użytkownik kliknął ten konkretny produkt")? Do tego służy właściwość typu EventCallback<T> oznaczona [Parameter] — rodzic przekazuje METODĘ do wywołania (<KartaProduktu OnKliknieto="ObslugaKlikniecia" />), a komponent potomny wywołuje ją w odpowiednim momencie przez await OnKliknieto.InvokeAsync(wartosc). To bezpośredni odpowiednik zdarzeń Clicked/Click podpinanych w XAML z działów WPF/MAUI, tylko teraz to TY definiujesz WŁASNE, niestandardowe zdarzenie na swoim komponencie.
Cykl życia komponentu — metody wywoływane automatycznie:
| Metoda | Kiedy się wykonuje |
|---|---|
OnInitialized() / OnInitializedAsync() | RAZ, przy pierwszym utworzeniu komponentu — dobre miejsce na pobranie początkowych danych (np. z bazy) |
OnParametersSet() | za KAŻDYM razem, gdy zmienią się parametry przekazane przez rodzica |
OnAfterRender(bool pierwszyRaz) | PO wyrenderowaniu komponentu w przeglądarce — jedyne bezpieczne miejsce na wywołania JavaScript (JS interop) albo operacje wymagające gotowego DOM |
Dispose() (interfejs IDisposable) | gdy komponent jest usuwany z ekranu — dobre miejsce na sprzątanie (np. zatrzymanie timera z poprzedniej lekcji) |
To bezpośredni odpowiednik konstruktora MainPage() i zdarzenia OnAppearing z lekcji o nawigacji w dziale MAUI — tylko w Blazor cykl życia ma WIĘCEJ, bardziej precyzyjnie rozdzielonych etapów.
Dyrektywa @ChildContent. Komponenty mogą też przyjmować DOWOLNĄ treść HTML/Razor MIĘDZY swoimi znacznikami otwierającym/zamykającym (jak <div>treść</div>) — właściwość [Parameter] public RenderFragment? ChildContent { get; set; } przechwytuje tę treść, a @ChildContent w widoku komponentu wskazuje, gdzie ją wstawić — przydatne przy budowaniu np. reużywalnej "karty" czy "okna dialogowego" o zmiennej zawartości.
Zobacz zależności
Schemat
Komponent RODZICA (np. ListaProduktow.razor)
│
│ <KartaProduktu Nazwa="Klawiatura" Cena="89.99"
│ OnKliknieto="ObsluzKlikniecie" />
▼
Komponent POTOMNY (KartaProduktu.razor)
[Parameter] public string Nazwa { get; set; } ← DANE W DÓŁ
[Parameter] public double Cena { get; set; }
[Parameter] public EventCallback<string> OnKliknieto { get; set; }
│
│ użytkownik klika kartę
▼
await OnKliknieto.InvokeAsync(Nazwa) ← ZDARZENIE W GÓRĘ
│
▼
Komponent RODZICA: ObsluzKlikniecie(string nazwa) { ... }
Cykl życia komponentu (kolejność wywołań):
OnInitialized() → OnParametersSet() → renderowanie → OnAfterRender(true)
│
│ (zmiana parametru od rodzica)
▼
OnParametersSet() → ponowne renderowanie → OnAfterRender(false)
Połącz z praktyką
Przykład z życia
Lista produktów w sklepie internetowym renderowana z wielu powtarzających się komponentów "Karta produktu" (nazwa, cena, przycisk "Dodaj do koszyka") — każda karta jest osobnym, samodzielnym komponentem, ale gdy użytkownik kliknie "Dodaj do koszyka" na KONKRETNEJ karcie, komponent rodzica (lista) musi się o tym dowiedzieć, żeby zaktualizować licznik koszyka widoczny gdzie indziej na stronie — dokładnie ten scenariusz pokazuje przykład w tej lekcji.