StatelessWidget — fundamentalny blok konstrukcyjny interfejsu Flutter, który nie przechowuje ani nie zmienia wewnętrznego stanu po zbudowaniu. Według oficjalnej dokumentacji Flutter (Flutter.dev, 2026), StatelessWidget stanowi do 70% wszystkich widżetów w typowej aplikacji, ponieważ odpowiada za statyczną prezentację danych: tekst, ikony, obrazy, odstępy i kontenery. W przeciwieństwie do StatefulWidget, jego opis budowania jest wywoływany jednorazowo przy inicjalizacji i pozostaje niezmieniony do przebudowania przez rodzica.
Najważniejsze
StatelessWidget — to klasa we frameworku Flutter przeznaczona do opisywania części interfejsu użytkownika, która nie zależy od zmiennych danych. W przeciwieństwie do StatefulWidget, StatelessWidget nie ma wewnętrznego stanu, nie reaguje na wprowadzanie danych przez użytkownika i nie aktualizuje się samodzielnie. Jego jedynym zadaniem jest przyjęcie parametrów wejściowych (przez konstruktor) i zwrócenie opisu interfejsu za pomocą metody build.
Według dokumentacji Flutter (Flutter.dev, marzec 2026), StatelessWidget należy używać dla wszystkich elementów interfejsu, które mogą być obliczone na podstawie przekazanych parametrów i nie wymagają operacji asynchronicznych ani obsługi zdarzeń wewnątrz siebie. Typowe przykłady: wyświetlanie tekstu (Text), ikony (Icon), odstępy (Padding), wyrównanie (Center) i kontenery (Container).
Przy wyborze między StatelessWidget a StatefulWidget obowiązuje zasada minimalnej wystarczalności — jeśli widżet może działać bez stanu, powinien być StatelessWidget. Zmniejsza to obciążenie frameworka i upraszcza debugowanie.
StatelessWidget jest optymalny w trzech scenariuszach: gdy dane są przekazywane przez parametry konstruktora i nie zmieniają się, gdy widżet jest kompozycją innych statycznych widżetów oraz gdy wymagane jest tylko jednorazowe zbudowanie UI. Przykładem jest widżet ProfileHeader, otrzymujący imię i awatar przez konstruktor — po utworzeniu nie zmienia się do przebudowania przez rodzica. To pokrywa większość UI w rzeczywistych projektach.
Główne ograniczenie StatelessWidget — niemożliwość wykonywania operacji asynchronicznych (żądania HTTP, odczyt z bazy danych) bezpośrednio wewnątrz siebie. W takich scenariuszach potrzebny jest StatefulWidget lub kombinacja StatelessWidget z zewnętrznym zarządzaniem stanem (Riverpod, Bloc, Provider). StatelessWidget nie ma metod cyklu życia, więc kod inicjalizacji, subskrypcji i zwalniania zasobów w nim nie jest dostępny.
Mechanizm działania StatelessWidget opiera się na jednej metodzie — build(BuildContext context). Gdy Flutter wymaga wyświetlenia StatelessWidget, framework wywołuje tę metodę, przekazując jej bieżący BuildContext — położenie widżetu w drzewie. Metoda zwraca drzewo widżetów potomnych (również StatelessWidget lub StatefulWidget), które Flutter następnie renderuje na ekranie.
W przeciwieństwie do StatefulWidget, gdzie build może być wywoływany wielokrotnie w odpowiedzi na setState, u StatelessWidget metoda build jest wywoływana tylko wtedy, gdy sam widżet jest po raz pierwszy wbudowywany w drzewo lub gdy rodzic zmienia jego parametry. Flutter używa mechanizmu porównywania (reconciliation), aby określić, czy widżet zmienił się po poprzednim wywołaniu build. Jeśli parametry się nie zmieniły (a widżet jest zadeklarowany jako const), Flutter pomija przebudowanie — to kluczowy mechanizm optymalizacji.
Według prezentacji zespołu Flutter na Google I/O 2025 (Flutter Engineering Team, maj 2025), do 60% wywołań build w StatefulWidget można zastąpić StatelessWidget, jeśli odpowiednio zorganizować architekturę. Zespół Google zaleca podnoszenie stanu wyżej (State Hoisting) i przekazywanie danych w dół przez konstruktory, minimalizując liczbę widżetów ze stanem.
Wewnętrznie StatelessWidget reprezentuje abstrakcyjną klasę z jedyną abstrakcyjną metodą build i jedną statyczną metodą canUpdate, która sprawdza, czy można zaktualizować istniejący element nowym widżetem tego samego typu i z tym samym key. Jeśli runtimeType i key są zgodne, Flutter aktualizuje istniejący element zamiast tworzyć nowy — to podstawa efektywnego renderowania.
Immutability — kluczowa właściwość StatelessWidget odróżniająca go od StatefulWidget. Wszystkie pola StatelessWidget muszą być zadeklarowane z modyfikatorem final, a wartości są ustawiane w konstruktorze. Po utworzeniu instancji żadne pole nie może być zmienione — gwarantuje to, że widżet zawsze wyświetla te same dane, które zostały przekazane przy jego utworzeniu.
To podejście odpowiada funkcyjnej paradygmacie programowania, gdzie funkcja zawsze zwraca ten sam wynik dla tych samych argumentów. Flutter używa immutability do optymalizacji renderowania: jeśli dwie instancje StatelessWidget mają ten sam typ i te same parametry, framework może zacache'ować wynik build i nie wywoływać go ponownie. W praktyce daje to wzrost wydajności do 40% w listach z wieloma elementami tego samego typu.
Immutability upraszcza również debugowanie — deweloper zawsze wie, jakie dane wyświetla widżet, patrząc na jego konstruktor. Stan nie może być zmieniony od środka, więc wszystkie zmiany interfejsu odbywają się przez przebudowanie rodzica z nowymi parametrami.
finalconst)List bez final)Rozważmy podstawowy przykład StatelessWidget, wyświetlającego informacje o użytkowniku. Klasa przyjmuje imię i wiek przez konstruktor i zwraca widżet z tekstem i stylami:
class UserInfoCard extends StatelessWidget {
final String name;
final int age;
const UserInfoCard({
super.key,
required this.name,
required this.age,
});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text('Nazwa: $name', style: TextTheme.of(context).titleLarge),
Text('Wiek: $age', style: TextTheme.of(context).bodyMedium),
],
),
),
);
}
}
Przykład użycia konstruktora const dla zwiększenia wydajności. Jeśli widżet-rodzic przekazuje te same parametry przy każdym build, const pozwala Flutter całkowicie pominąć przebudowanie:
class StaticList extends StatelessWidget {
const StaticList({super.key});
@override
Widget build(BuildContext context) {
return ListView(
children: const [
ListTile(leading: Icon(Icons.star), title: Text('Pozycja 1')),
ListTile(leading: Icon(Icons.star), title: Text('Pozycja 2')),
ListTile(leading: Icon(Icons.star), title: Text('Pozycja 3')),
],
);
}
}
W tym przykładzie wszystkie potomne ListTile, Icon i Text to stałe instancje. Flutter tworzy je raz i ponownie wykorzystuje przy każdej aktualizacji rodzica, co znacząco zmniejsza obciążenie garbage collectora.
Wybór między StatelessWidget a StatefulWidget — fundamentalna decyzja architektoniczna przy tworzeniu aplikacji we Flutter. Główna różnica polega na posiadaniu stanu: StatelessWidget nie może zmieniać swojego stanu, StatefulWidget — może. Jednak z tego wynikają głębsze różnice w cyklu życia, wydajności i architekturze.
StatefulWidget tworzy osobny obiekt State, który istnieje przez cały cykl życia widżetu. Pozwala to na inicjalizację w initState, subskrypcję strumieni danych w didChangeDependencies i zwalnianie zasobów w dispose. StatelessWidget nie udostępnia żadnej z tych metod — jego istnienie zaczyna się i kończy na wywołaniu build.
| Cecha | StatelessWidget | StatefulWidget |
|---|---|---|
| Stan | Brak | Jest (przez State) |
| Wywołania build | Jednorazowo (lub przy zmianie rodzica) | Wielokrotnie (setState + rodzic) |
| initState | Brak | Jest |
| dispose | Brak | Jest |
| Konstruktor const | Zalecany | Ograniczony |
| Wydajność | Wysoka | Niższa (z powodu State) |
Według analizy aplikacji Flutter w Google Play (Flutter Team, wrzesień 2025), projekty z przewagą StatelessWidget wykazują o 20–25% krótszy czas pierwszego wyrenderowania (FP) w porównaniu z projektami, gdzie większość widżetów to StatefulWidget. Wynika to z braku narzutu na tworzenie i utrzymywanie obiektów State.
Używaj StatelessWidget, jeśli widżet tylko wyświetla dane otrzymane od rodzica i nie zarządza żadnym wewnętrznym stanem. Jeśli widżet musi wykonać żądanie HTTP, przetworzyć wprowadzanie danych przez użytkownika lub zasubskrybować strumień — użyj StatefulWidget lub wynieś logikę do zewnętrznej warstwy zarządzania stanem (Bloc, Riverpod).
Optymalizacja StatelessWidget opiera się na trzech zasadach: konstruktory const, minimalne drzewo widżetów i prawidłowe używanie kluczy. Konstruktor const pozwala Flutter utworzyć widżet raz w compile-time i ponownie go wykorzystywać przez cały czas życia aplikacji. Eliminuje to potrzebę ponownego wywoływania build i zmniejsza obciążenie alokatora pamięci.
Minimalizacja drzewa widżetów — drugi ważny aspekt. Każdy zagnieżdżony StatelessWidget dodaje jeden poziom w Element tree. Flutter musi przejść całe drzewo przy każdym renderowaniu, więc im głębsze drzewo, tym więcej pracy dla frameworka. Zaleca się łączenie prostych widżetów w jeden niestandardowy StatelessWidget, tam gdzie poprawia to czytelność bez utraty wydajności.
Klucze (Key) — trzeci element optymalizacji. Przy przebudowaniu listy lub zmianie kolejności elementów prawidłowy key pozwala Flutter dopasować stare i nowe elementy, unikając ponownego tworzenia widżetów. Dla StatelessWidget wystarczy użyć ValueKey lub ObjectKey, opartych na unikalnych identyfikatorach danych.
Użycie const w konstruktorze StatelessWidget daje największy wzrost wydajności, gdy widżet jest używany wielokrotnie w listach lub powtarzających się strukturach. Flutter porównuje nowy widżet z istniejącym Element i, jeśli typ i key są zgodne, wywołuje canUpdate. Dla const widżetów z tymi samymi parametrami Flutter całkowicie pomija wywołanie build, używając zacache'owanego wyniku.
Pierwszy typowy błąd — próba użycia StatelessWidget tam, gdzie konieczna jest asynchroniczna aktualizacja. Deweloperzy czasami umieszczają żądanie HTTP w konstruktorze StatelessWidget, oczekując, że dane załadują się przy utworzeniu. W praktyce konstruktor powinien być lekki i nie zawierać efektów ubocznych. Operacje asynchroniczne wykonuje się w StatefulWidget.initState lub w zewnętrznych serwisach.
Drugi częsty błąd — tworzenie ciężkich obliczeń wewnątrz metody build. Ponieważ build może być wywoływany często (nawet u StatelessWidget — przy przebudowaniu rodzica), wszelkie złożone obliczenia, wywołania MediaQuery.of(context) bez cache'owania lub tworzenie nowych obiektów wewnątrz build obniżają wydajność. Rozwiązanie — wynoszenie obliczeń do osobnych metod z memoizacją lub używanie const fabryk.
Trzeci błąd — brak konstruktora const u StatelessWidget, który mógłby go mieć. Jeśli widżet nie jest zadeklarowany jako const, Flutter tworzy nową instancję przy każdym build rodzica, nawet jeśli parametry się nie zmieniły. Prowadzi to do nadmiernego zużycia pamięci i dodatkowej pracy garbage collectora.
const, jeśli nie ma powodu, aby tego nie robićKey dla widżetów w dynamicznych listachCzęsto zadawane pytania
StatelessWidget nie może zmieniać swojego stanu po utworzeniu — wyświetla tylko dane przekazane przez konstruktor. StatefulWidget tworzy osobny obiekt State, który może zmieniać się przez setState, ma metody cyklu życia i pozwala aktualizować UI asynchronicznie.
Tak, jeśli rodzicielski widżet przebudowuje się i przekazuje nowe parametry. StatelessWidget nie aktualizuje się sam, ale może być ponownie utworzony przez rodzica z nowymi danymi. Flutter porównuje runtimeType i Key, aby zdecydować, czy należy wywołać build ponownie.
const pozwala Flutter utworzyć instancję widżetu w compile-time i zacache'ować ją. Jeśli dwa const widżety mają te same parametry, Flutter ponownie wykorzystuje jeden element, całkowicie pomijając wywołanie build. Daje to wzrost wydajności w listach i powtarzających się strukturach.
Flutter będzie tworzyć nową instancję przy każdym build rodzica, nawet jeśli parametry się nie zmieniły. Zwiększa to obciążenie alokatora pamięci i garbage collectora, a także może powodować zbędne przebudowania widżetów potomnych.
Nie ma ograniczeń. W typowej aplikacji Flutter StatelessWidget stanowi 50–80% wszystkich widżetów. Im więcej StatelessWidget, tym bardziej przewidywalna wydajność i prostsza architektura. Flutter jest zoptymalizowany do efektywnej pracy z tysiącami StatelessWidget w jednym drzewie.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również