InheritedWidget — egy speciális widget a Flutter-ben, amely adatokat továbbít lefelé a widgetfában anélkül, hogy explicit átadásra lenne szükség a konstruktorokon keresztül. A gyermek widgetek a BuildContext-en keresztül férnek hozzá az adatokhoz és automatikusan feliratkoznak a frissítésekre. Amikor az InheritedWidget adatai megváltoznak, az összes függő widget újraépül. A Flutter API Reference, 2025 szerint az InheritedWidget a Theme, MediaQuery, Localizations és a legtöbb állapotkezelő könyvtár alapját képezi.
Főbb pontok
InheritedWidget — egy widget, amely az adatait elérhetővé teszi az összes leszármazott számára a Widget Tree-ben. Ellentétben a hétköznapi widgettel, amely csak a konstruktoron keresztül továbbít adatokat a gyermek elemeknek, az InheritedWidget lehetővé teszi bármely widget számára az al-fában, hogy hozzáférjen az adatokhoz paraméterlánc nélkül. Ez megoldja a "prop drilling" problémáját — adatok továbbítását számos köztes widgeten keresztül, amelyek maguk nem használják ezeket az adatokat.
A Flutter számos beépített InheritedWidget-ot tartalmaz: Theme (színséma és stílusok), MediaQuery (képernyőméret, tájolás, pixelsűrűség), Localizations (lokalizált karakterláncok), Directionality (szöveg iránya), DefaultTextStyle (alapértelmezett szövegstílus). Ezeket a widgeteket olyan gyökér widgetek állítják be, mint a MaterialApp, és az egész alkalmazásban elérhetőek.
InheritedWidget nem rendelkezik saját állapottal — a konstruktoron keresztül átadott adatokat tárolja. Amikor az InheritedWidget szülője új adatokkal újraépül, az updateShouldNotify metódus meghívódik a régi és új adatok összehasonlítására. Ha a metódus true-t ad vissza, az összes függő widget megjelölésre kerül az újraépítéshez. Ez egy egyszerű, de hatékony reaktív frissítési mechanizmus.
Az adatátviteli mechanizmus az InheritedWidget-on keresztül az Element Tree-n alapul. Amikor egy widget meghívja a dependOnInheritedWidgetOfExactType-ot, a megfelelő elem regisztrál egy függőséget az InheritedElement-től. Az InheritedWidget változásakor az InheritedElement értesíti az összes függő elemet, amelyek a következő képkockában újraépülnek.
A dependOnInheritedWidgetOfExactType metódus nem csak megtalálja az InheritedWidget-ot a fában — feliratkoztatja az aktuális elemet az értesítésekre. Ha a dependOn helyett a findAncestorWidgetOfExactType-ot használná, a widget megkapná az adatokat, de nem épülne újra azok változásakor. Ez egy fontos különbség: a dependOn feliratkozás, a findAncestor egyszeri keresés.
Amikor egy widget InheritedWidget-ot kér, a Flutter felemelkedik az Element Tree-n az aktuális elemtől a gyökérig, ellenőrizve minden InheritedElement-et a típus egyezésére. Az első megtalált InheritedElement kerül visszaadásra. Ez azt jelenti, hogy a fában a legközelebbi InheritedWidget rendelkezik elsőbbséggel — felülírhatja az adatokat egy adott szinten az InheritedWidget közelebb helyezésével a leszármazottakhoz.
class ThemeData {
final Color primaryColor;
final TextTheme textTheme;
const ThemeData({required this.primaryColor, required this.textTheme});
}
class MyTheme extends InheritedWidget {
final ThemeData data;
const MyTheme({required this.data, required Widget child}) : super(child: child);
static MyTheme of(BuildContext context) {
final widget = context.dependOnInheritedWidgetOfExactType<MyTheme>();
assert(widget != null, "MyTheme not found in tree");
return widget!;
}
@override
bool updateShouldNotify(MyTheme oldWidget) => oldWidget.data != data;
}
Ebben a példában a MyTheme a statikus of metódust használja az adatok leszármazottaknak történő biztosítására. A dependOnInheritedWidgetOfExactType metódus regisztrálja a függőséget, az updateShouldNotify pedig összehasonlítja a régi és új adatokat a függő widgetek újraépítésének szükségességének meghatározásához.
A saját InheritedWidget létrehozása két lépésből áll: az InheritedWidget-ből öröklődő osztály meghatározása és a statikus of metódus implementációja a leszármazottakból való hozzáféréshez. Az adatok a konstruktoron keresztül kerülnek átadásra, az updateShouldNotify metódus pedig meghatározza, hogy a függő widgeteknek mikor kell újraépülniük.
Az osztálynak az InheritedWidget-ből kell örökölnie és a konstruktoron keresztül kell fogadnia az adatokat a kötelező child paraméterrel. Az adatok bármilyen típusúak lehetnek: primitívek, objektumok, függvények. A fő szabály — az adatoknak megváltoztathatatlannak (immutable) kell lenniük, hogy a régi és új értékek megbízhatóan összehasonlíthatóak legyenek.
A statikus of metódus egy BuildContext-et fogad és visszaadja az InheritedWidget adatait. Belül a dependOnInheritedWidgetOfExactType kerül meghívásra, amely a legközelebbi InheritedWidget-ot keresi a megadott típusból a fában. Ha az InheritedWidget nem található, a metódus az implementációtól függően vagy kivételt dob, vagy alapértelmezett értéket ad vissza.
Az adatok eléréséhez a widget meghívja a MyWidget.of(context)-ot a build metóduson belül. A Flutter automatikusan feliratkoztatja a widgetet a frissítésekre. Ha az adatok megváltoznak, a widget a következő képkockában újraépül. Ez lehetővé teszi tiszta és deklaratív kód létrehozását felesleges paraméterek nélkül.
class UserPreferences extends InheritedWidget {
final String languageCode;
final bool darkMode;
const UserPreferences({
required this.languageCode,
required this.darkMode,
required Widget child,
}) : super(child: child);
static UserPreferences of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<UserPreferences>()!;
}
@override
bool updateShouldNotify(UserPreferences oldWidget) =>
oldWidget.languageCode != languageCode || oldWidget.darkMode != darkMode;
}
Ebben a példában a UserPreferences tárolja a felhasználói beállításokat. Az updateShouldNotify metódus minden mezőt külön-külön hasonlít össze, ami megakadályozza a szükségtelen újraépüléseket, amikor csak egy paraméter változik. Használjon hasonló megközelítést a saját, több mezővel rendelkező InheritedWidget-jához.
updateShouldNotify — az InheritedWidget kulcsfontosságú metódusa, amely meghatározza, hogy értesíteni kell-e a függő widgeteket az adatok változásáról. Ha a metódus false-t ad vissza, a függő widgetek nem épülnek újra, még akkor sem, ha maga az InheritedWidget új példányt kapott ugyanazokkal az adatokkal. Ez kritikus fontosságú a teljesítmény szempontjából.
Csak azokat a mezőket hasonlítsa össze, amelyek ténylegesen megváltoztak és befolyásolják a megjelenítést. Ha az InheritedWidget 10 mezőt tartalmaz, de csak egy befolyásolja a UI-t, csak azt a mezőt ellenőrizze. Gyűjteményekhez használjon mély összehasonlítást vagy megváltoztathatatlan adatstruktúrákat. Ne használja a ==-t List vagy Map esetén, mivel ezek referencia szerint kerülnek összehasonlításra.
A leggyakoribb hiba — a true visszaadása összehasonlítás nélkül. Ez az összes függő widget újraépítéséhez vezet a szülő minden frissítésekor, még akkor is, ha az adatok nem változtak. A második hiba — a false visszaadása, amikor az adatok megváltoztak, ami elavult UI-hoz vezet. A harmadik — összetett összehasonlítás, amely minden képkockában végrehajtódik és lassítja a működést.
InheritedWidget és a callbackek (függvények átadása a konstruktoron keresztül) különböző feladatokat oldanak meg. Az InheritedWidget olyan adatokhoz alkalmas, amelyekre sok widgetnek van szüksége a fa különböző szintjein. A callbackek kényelmesek az események egyirányú továbbítására a szülőtől egy adott gyermekhez vagy fordítva. A választás az alkalmazás architektúrájától és a változtatások gyakoriságától függ.
Használja az InheritedWidget-ot, amikor az adatokra sok widgetnek van szüksége a beágyazottság különböző szintjein: alkalmazás téma, felhasználói beállítások, eszköz információ, aktuális munkamenet adatai. Az InheritedWidget különösen hatékony a "globális" adatokhoz, amelyek ritkán változnak, de a UI különböző részein szükségesek.
Callbackek (visszahívó függvények) alkalmasak események továbbítására a gyermek widgettől a szülő felé: gombnyomás, listaelem kiválasztása, űrlap elküldése. A callbackek explicit módon jelzik, hogy a gyermek milyen műveleteket végezhet, és nem hoznak létre rejtett függőségeket. Az adatok lefelé történő továbbításához a fában kis számú szint esetén szintén egyszerűbb a konstruktor paramétereinek használata.
| Kritérium | InheritedWidget | Callbackek |
|---|---|---|
| Irány | Fentről lefelé (szülő → leszármazottak) | Alulról felfelé (gyermek → szülő) vagy közvetlen |
| Terjedelem | Teljes al-fa | Konkrét widget |
| Újraépítés | Automatikus az adatok változásakor | Kézi setState szükséges |
| Komplexitás | Közepes (szükséges az InheritedWidget osztály) | Alacsony (egyszerű függvény) |
Provider és Riverpod — népszerű állapotkezelő könyvtárak a Flutter-ben, amelyek az InheritedWidget-re épülnek. Kibővítik annak képességeit: hozzáadják a ChangeNotifier támogatást, automatikus eltávolítást a szétszereléskor, lusta inicializálást és egyszerűsített szintaxist a generikusokon keresztül.
Provider az InheritedWidget-ot használja bármilyen típusú objektum lefelé továbbítására a fában. A ChangeNotifierProvider a ChangeNotifier-en keresztül követi a változásokat és meghívja az updateShouldNotify-ot a notifyListeners meghívásakor. Ez megszabadítja a fejlesztőt az InheritedWidget manuális létrehozásától és az updateShouldNotify implementációjától.
A közvetlen InheritedWidget több kontrollt ad és nem igényel külső függőségeket. A Provider kész infrastruktúrát biztosít: Consumer, Selector, MultiProvider, ProxyProvider. A választás az alkalmazás komplexitásától függ. Egyszerű projektekhez a közvetlen InheritedWidget elegendő, nagy projektekhez a Provider vagy a Riverpod csökkenti a sablon kódot.
// Közvetlen InheritedWidget
class UserProvider extends InheritedWidget {
final UserData userData;
const UserProvider({required this.userData, required Widget child}) : super(child: child);
static UserData of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<UserProvider>()!.userData;
@override
bool updateShouldNotify(UserProvider old) => old.userData != userData;
}
// Provider megfelelő
return ChangeNotifierProvider<UserData>(
create: (_) => UserData(),
child: MyApp(),
);
Mindkét megközelítés a példában ugyanazt a feladatot oldja meg — a UserData továbbítását lefelé a fában. Provider csökkenti a kód mennyiségét, de elrejti az InheritedWidget mechanikáját. A közvetlen InheritedWidget teljes kontrollt és megértést biztosít a történésekről, ami különösen fontos a Flutter tanulásakor és az összetett újraépítési problémák hibakeresésekor.
Gyakran Ismételt Kérdések
InheritedWidget az adatokat a BuildContext-en keresztül minden leszármazott számára elérhetővé teszi, míg a hétköznapi widget csak a konstruktoron keresztül továbbít adatokat. Az InheritedWidget emellett feliratkoztatja a leszármazottakat az adatok frissítéseire.
A függő widgetek csak akkor épülnek újra, amikor az updateShouldNotify true-t ad vissza. Ha a metódus helyesen van implementálva, az újraépítés csak az adatok tényleges változásakor történik, nem a szülő minden egyes rebuild-jekor.
Igen, bármilyen számú InheritedWidget használható egy fában. Mindegyik egy adott típusú adatot biztosít, és a widgetek egyszerre több InheritedWidget-ból is kaphatnak adatokat.
dependOn feliratkoztatja a widgetet a frissítésekre — az adatok változásakor a widget újraépül. findAncestor egyszeri keresést végez feliratkozás nélkül, és a widget nem fog tudni az adatok változásairól.
Egyszerű állapothoz (téma, beállítások) az InheritedWidget elegendő. Az üzleti logikával rendelkező összetett állapothoz használja a Provider, Riverpod vagy BLoC könyvtárakat — ezek az InheritedWidget-re épülnek és hozzáadják a szükséges infrastruktúrát.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is