InheritedWidget — är en speciell widget i Flutter som skickar data nedåt i widgetträdet utan explicit överföring via konstruktorer. Underordnade widgets får åtkomst till data via BuildContext och prenumererar automatiskt på uppdateringar. När data i InheritedWidget ändras, återbyggs alla beroende widgets. Enligt Flutter API Reference, 2025 ligger InheritedWidget till grund för Theme, MediaQuery, Localizations och de flesta bibliotek för tillståndshantering.
Huvudpunkter
InheritedWidget — är en widget som gör sin data tillgänglig för alla ättlingar i Widget Tree. Till skillnad från en vanlig widget, som bara skickar data via konstruktorn till underordnade element, tillåter InheritedWidget vilken widget som helst i underträdet att komma åt data utan en parameterkedja. Detta löser problemet med "prop drilling" — att skicka data genom flera mellanliggande widgets som själva inte använder denna data.
Flutter innehåller flera inbyggda InheritedWidgets: Theme (färgschema och stilar), MediaQuery (skärmstorlek, orientering, pixeldensitet), Localizations (lokaliserade strängar), Directionality (textriktning), DefaultTextStyle (standardtextstil). Dessa widgets sätts av rotwidgets som MaterialApp och är tillgängliga i hela appen.
InheritedWidget har inget eget tillstånd — det lagrar data som skickats via konstruktorn. När föräldern till InheritedWidget återbyggs med ny data, anropas metoden updateShouldNotify för att jämföra gammal och ny data. Om metoden returnerar true, markeras alla beroende widgets för återbyggnad. Detta är en enkel men effektiv mekanism för reaktiv uppdatering.
Mekanismen för dataöverföring via InheritedWidget är baserad på Element Tree. När en widget anropar dependOnInheritedWidgetOfExactType, registrerar motsvarande element ett beroende på InheritedElement. När InheritedWidget ändras, meddelar InheritedElement alla beroende element, som återbyggs i nästa bildruta.
Metoden dependOnInheritedWidgetOfExactType hittar inte bara InheritedWidget i trädet — den prenumererar det aktuella elementet på meddelanden. Om du skulle använda findAncestorWidgetOfExactType istället för dependOn, skulle widgeten få data men inte återbyggas när den ändras. Detta är en viktig skillnad: dependOn är en prenumeration, findAncestor är en engångssökning.
När en widget begär InheritedWidget, stiger Flutter uppför Element Tree från det aktuella elementet till roten, och kontrollerar varje InheritedElement för typmatchning. Det första hittade InheritedElement returneras. Detta innebär att den närmaste InheritedWidget i trädet har prioritet — du kan åsidosätta data på en viss nivå genom att placera InheritedWidget närmare ättlingarna.
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;
}
I detta exempel använder MyTheme den statiska metoden of för att tillhandahålla data till ättlingar. Metoden dependOnInheritedWidgetOfExactType registrerar beroendet och updateShouldNotify jämför gammal och ny data för att avgöra behovet av återbyggnad av beroende widgets.
Att skapa en egen InheritedWidget består av två steg: definiera en klass som ärver InheritedWidget och implementera en statisk metod of för åtkomst från ättlingar. Data skickas via konstruktorn och metoden updateShouldNotify avgör när beroende widgets ska återbyggas.
Klassen måste ärva InheritedWidget och ta emot data via konstruktorn med den obligatoriska parametern child. Data kan vara av vilken typ som helst: primitiver, objekt, funktioner. Huvudregeln — data måste vara oföränderlig (immutable) för att på ett tillförlitligt sätt kunna jämföra gamla och nya värden.
Den statiska metoden of tar emot en BuildContext och returnerar InheritedWidgets data. Internt anropas dependOnInheritedWidgetOfExactType, som söker efter den närmaste InheritedWidget av angiven typ i trädet. Om InheritedWidget inte hittas, kastar metoden ett undantag eller returnerar ett standardvärde beroende på implementeringen.
För att komma åt data anropar widgeten MyWidget.of(context) inuti build-metoden. Flutter prenumererar automatiskt widgeten på uppdateringar. Om data ändras, kommer widgeten att återbyggas i nästa bildruta. Detta möjliggör ren och deklarativ kod utan onödiga parametrar.
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;
}
I detta exempel lagrar UserPreferences användarpreferenser. Metoden updateShouldNotify jämför varje fält separat, vilket förhindrar onödiga återbyggnader när bara en parameter ändras. Använd ett liknande tillvägagångssätt för din egen InheritedWidget med flera fält.
updateShouldNotify — är den viktigaste metoden i InheritedWidget som avgör om beroende widgets ska meddelas om dataändring. Om metoden returnerar false, återbyggs inte beroende widgets, även om InheritedWidget själv har fått en ny instans med samma data. Detta är avgörande för prestanda.
Jämför endast de fält som faktiskt har ändrats och påverkar visningen. Om InheritedWidget innehåller 10 fält men bara ett påverkar UI, kontrollera endast det fältet. För samlingar, använd djup jämförelse eller oföränderliga datastrukturer. Använd inte == för List eller Map, eftersom de jämförs via referens.
Det vanligaste felet — att returnera true utan jämförelse. Detta leder till återbyggnad av alla beroende widgets vid varje uppdatering av föräldern, även om data inte har ändrats. Det andra felet — att returnera false när data har ändrats, vilket leder till föråldrat UI. Det tredje — en komplex jämförelse som körs varje bildruta och saktar ner prestanda.
InheritedWidget och callbacks (att skicka funktioner via konstruktorn) löser olika uppgifter. InheritedWidget är lämplig för data som behövs av många widgets på olika nivåer i trädet. Callbacks är praktiska för envägssändning av händelser från förälder till ett specifikt barn eller vice versa. Valet beror på appens arkitektur och frekvensen av ändringar.
Använd InheritedWidget när data behövs av många widgets på olika nivåer av nästling: apptema, användarpreferenser, enhetsinformation, data för aktuell session. InheritedWidget är särskilt effektiv för "global" data som sällan ändras men behövs i olika delar av UI.
Callbacks (återanropsfunktioner) är lämpliga för att skicka händelser från en underordnad widget till den överordnade: knapptryckning, val av listobjekt, formulärinskickning. Callbacks visar explicit vilka åtgärder barnet kan utföra och skapar inte dolda beroenden. För att skicka data nedåt i trädet över ett litet antal nivåer är det också enklare att använda konstruktorparametrar.
| Kriterium | InheritedWidget | Callbacks |
|---|---|---|
| Riktning | Uppifrån och ned (förälder → ättlingar) | Nerifrån och upp (barn → förälder) eller direkt |
| Område | Hela underträdet | Specifik widget |
| Återbyggnad | Automatisk vid dataändring | Kräver manuell setState |
| Komplexitet | Medel (kräver InheritedWidget-klass) | Låg (enkel funktion) |
Provider och Riverpod — populära bibliotek för tillståndshantering i Flutter, byggda på InheritedWidget. De utökar dess möjligheter: lägger till stöd för ChangeNotifier, automatisk borttagning vid demontering, lat initialisering och förenklad syntax via generika.
Provider använder InheritedWidget för att skicka ett objekt av valfri typ nedåt i trädet. ChangeNotifierProvider spårar ändringar via ChangeNotifier och anropar updateShouldNotify när notifyListeners anropas. Detta befriar utvecklaren från att manuellt skapa InheritedWidget och implementera updateShouldNotify.
Direkt InheritedWidget ger mer kontroll och kräver inga externa beroenden. Provider tillhandahåller färdig infrastruktur: Consumer, Selector, MultiProvider, ProxyProvider. Valet beror på appens komplexitet. För enkla projekt räcker direkt InheritedWidget, för stora projekt minskar Provider eller Riverpod mallen.
// Direkt 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-motsvarighet
return ChangeNotifierProvider<UserData>(
create: (_) => UserData(),
child: MyApp(),
);
Båda tillvägagångssätten i exemplet löser samma uppgift — att skicka UserData nedåt i trädet. Provider minskar mängden kod men döljer mekaniken i InheritedWidget. Direkt InheritedWidget ger full kontroll och förståelse för vad som händer, vilket är särskilt viktigt när man lär sig Flutter och felsöker komplexa återbyggnadsproblem.
Vanliga frågor
InheritedWidget gör data tillgänglig för alla ättlingar via BuildContext, medan en vanlig widget bara skickar data via konstruktorn. InheritedWidget prenumererar också ättlingar på datauppdateringar.
Beroende widgets återbyggs bara när updateShouldNotify returnerar true. Om metoden är korrekt implementerad sker återbyggnad endast vid faktisk dataändring, inte vid varje rebuild av föräldern.
Ja, du kan använda valfritt antal InheritedWidgets i samma träd. Varje en tillhandahåller data av en specifik typ och widgets kan ta emot data från flera InheritedWidgets samtidigt.
dependOn prenumererar widgeten på uppdateringar — när data ändras återbyggs widgeten. findAncestor utför en engångssökning utan prenumeration och widgeten kommer inte att få veta om dataändringar.
För enkelt tillstånd (tema, inställningar) räcker InheritedWidget. För komplext tillstånd med affärslogik, använd Provider, Riverpod eller BLoC — de är byggda på InheritedWidget och lägger till nödvändig infrastruktur.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också