InheritedWidget — ay isang espesyal na widget sa Flutter na nagpapadala ng data pababa sa puno ng widget nang walang tahasang pagpasa sa pamamagitan ng mga konstruktor. Ang mga child widget ay nakakakuha ng access sa data sa pamamagitan ng BuildContext at awtomatikong nag-subscribe sa mga update. Kapag nagbago ang data sa InheritedWidget, lahat ng umaasang widget ay muling itinatayo. Ayon sa Flutter API Reference, 2025, ang InheritedWidget ay nasa pundasyon ng Theme, MediaQuery, Localizations at karamihan sa mga library ng pamamahala ng estado.
Mga Pangunahing Punto
InheritedWidget — ay isang widget na ginagawang accessible ang data nito sa lahat ng mga inapo sa Widget Tree. Hindi tulad ng isang ordinaryong widget, na nagpapadala lamang ng data sa pamamagitan ng konstruktor sa mga child element, pinapayagan ng InheritedWidget ang sinumang widget sa sub-tree na ma-access ang data nang walang chain ng mga parameter. Nilulutas nito ang problema ng "prop drilling" — pagpapadala ng data sa pamamagitan ng maraming intermediary widget na hindi mismo gumagamit ng data na ito.
Ang Flutter ay may kasamang ilang built-in na InheritedWidget: Theme (color scheme at styles), MediaQuery (laki ng screen, oryentasyon, pixel density), Localizations (na-localize na mga string), Directionality (direksyon ng teksto), DefaultTextStyle (default na style ng teksto). Ang mga widget na ito ay itinakda ng mga root widget tulad ng MaterialApp at available sa buong app.
InheritedWidget ay walang sariling estado — iniimbak nito ang data na ipinasa sa pamamagitan ng konstruktor. Kapag ang parent ng InheritedWidget ay muling itinayo gamit ang bagong data, ang updateShouldNotify na paraan ay tinatawag upang ihambing ang luma at bagong data. Kung ang paraan ay nagbalik ng true, lahat ng umaasang widget ay minamarkahan para sa muling pagtatayo. Ito ay isang simple ngunit epektibong mekanismo ng reaktibong pag-update.
Ang mekanismo ng paglipat ng data sa pamamagitan ng InheritedWidget ay batay sa Element Tree. Kapag ang isang widget ay tumawag ng dependOnInheritedWidgetOfExactType, ang kaukulang elemento ay nagrerehistro ng dependency sa InheritedElement. Kapag nagbago ang InheritedWidget, ang InheritedElement ay nag-aabiso sa lahat ng umaasang elemento, na muling itinatayo sa susunod na frame.
Ang paraang dependOnInheritedWidgetOfExactType ay hindi lamang nakakahanap ng InheritedWidget sa puno — ito ay nag-subscribe sa kasalukuyang elemento sa mga abiso. Kung gagamitin mo ang findAncestorWidgetOfExactType sa halip na dependOn, makakatanggap ang widget ng data ngunit hindi muling itatayo kapag nagbago ang mga ito. Ito ay isang mahalagang pagkakaiba: ang dependOn ay subscription, ang findAncestor ay isang beses na paghahanap.
Kapag ang isang widget ay humiling ng InheritedWidget, ang Flutter ay umakyat sa Element Tree mula sa kasalukuyang elemento patungo sa ugat, sinusuri ang bawat InheritedElement para sa pagtutugma ng uri. Ang unang natagpuang InheritedElement ay ibinabalik. Ito ay nangangahulugan na ang pinakamalapit na InheritedWidget sa puno ay may priyoridad — maaari mong i-override ang data sa isang partikular na antas sa pamamagitan ng paglalagay ng InheritedWidget na mas malapit sa mga inapo.
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;
}
Sa halimbawang ito, MyTheme ay gumagamit ng static na paraan na of upang magbigay ng data sa mga inapo. Ang dependOnInheritedWidgetOfExactType na paraan ay nagrerehistro ng dependency, at ang updateShouldNotify ay naghahambing ng luma at bagong data upang matukoy ang pangangailangan para sa muling pagtatayo ng mga umaasang widget.
Ang paglikha ng sarili mong InheritedWidget ay binubuo ng dalawang hakbang: pagtukoy ng klase na nagmamana ng InheritedWidget at pagpapatupad ng static na paraan na of para sa access mula sa mga inapo. Ang data ay ipinapasa sa pamamagitan ng konstruktor, at ang updateShouldNotify na paraan ay tumutukoy kung kailan dapat muling itayo ang mga umaasang widget.
Ang klase ay dapat magmana ng InheritedWidget at tumanggap ng data sa pamamagitan ng konstruktor na may mandatoryong parameter na child. Ang data ay maaaring maging anumang uri: primitives, objects, functions. Ang pangunahing patakaran — ang data ay dapat na hindi nababago (immutable) upang mapagkakatiwalaang maihambing ang luma at bagong halaga.
Ang static na paraan na of ay tumatanggap ng BuildContext at nagbabalik ng data ng InheritedWidget. Sa loob, ang dependOnInheritedWidgetOfExactType ay tinatawag, na naghahanap ng pinakamalapit na InheritedWidget ng tinukoy na uri sa puno. Kung hindi natagpuan ang InheritedWidget, ang paraan ay nagtatapon ng exception o nagbabalik ng default na halaga depende sa implementasyon.
Upang ma-access ang data, ang widget ay tumatawag ng MyWidget.of(context) sa loob ng build na paraan. Awtomatikong ini-subscribe ng Flutter ang widget sa mga update. Kung magbago ang data, ang widget ay muling itatayo sa susunod na frame. Ito ay nagpapahintulot sa paglikha ng malinis at deklaratibong code nang walang hindi kinakailangang mga parameter.
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;
}
Sa halimbawang ito, UserPreferences ay nag-iimbak ng mga kagustuhan ng user. Ang updateShouldNotify na paraan ay naghahambing ng bawat field nang hiwalay, na pumipigil sa hindi kinakailangang muling pagtatayo kapag isang parameter lamang ang nagbago. Gumamit ng katulad na diskarte para sa iyong sariling InheritedWidget na may maraming field.
updateShouldNotify — ay ang pangunahing paraan ng InheritedWidget na tumutukoy kung kailangan bang abisuhan ang mga umaasang widget tungkol sa pagbabago ng data. Kung ang paraan ay nagbalik ng false, ang mga umaasang widget ay hindi muling itatayo, kahit na ang InheritedWidget mismo ay nakatanggap ng bagong instance na may parehong data. Ito ay kritikal para sa pagganap.
Ihambing lamang ang mga field na talagang nagbago at nakakaapekto sa pagpapakita. Kung ang InheritedWidget ay naglalaman ng 10 field ngunit isa lamang ang nakakaapekto sa UI, suriin lamang ang field na iyon. Para sa mga koleksyon, gumamit ng malalim na paghahambing o mga istraktura ng data na hindi nababago. Huwag gumamit ng == para sa List o Map, dahil ang mga ito ay inihahambing sa pamamagitan ng reference.
Ang pinakakaraniwang pagkakamali — pagbabalik ng true nang walang paghahambing. Ito ay humahantong sa muling pagtatayo ng lahat ng umaasang widget sa bawat update ng parent, kahit na hindi nagbago ang data. Ang pangalawang pagkakamali — pagbabalik ng false kapag nagbago ang data, na humahantong sa lumang UI. Ang pangatlo — kumplikadong paghahambing na isinasagawa bawat frame at nagpapabagal sa pagganap.
InheritedWidget at callback (pagpasa ng mga function sa pamamagitan ng konstruktor) ay lumulutas ng iba't ibang gawain. Ang InheritedWidget ay angkop para sa data na kailangan ng maraming widget sa iba't ibang antas ng puno. Ang callback ay maginhawa para sa one-way na pagpapadala ng mga kaganapan mula sa parent patungo sa isang partikular na child o kabaliktaran. Ang pagpili ay depende sa arkitektura ng app at dalas ng mga pagbabago.
Gamitin ang InheritedWidget kapag ang data ay kailangan ng maraming widget sa iba't ibang antas ng pagkakasama-sama: tema ng app, mga kagustuhan ng user, impormasyon ng device, data ng kasalukuyang session. Ang InheritedWidget ay lalong epektibo para sa "global" na data na bihirang magbago ngunit kailangan sa iba't ibang bahagi ng UI.
Callback (mga function na pabalik) ay angkop para sa pagpapadala ng mga kaganapan mula sa child widget patungo sa parent: pagpindot ng button, pagpili ng item sa listahan, pagpapadala ng form. Ang callback ay tahasang nagpapakita kung anong mga aksyon ang maaaring gawin ng child at hindi lumilikha ng mga nakatagong dependency. Para sa pagpapadala ng data pababa sa puno sa maliit na bilang ng mga antas, mas simple ring gumamit ng mga parameter ng konstruktor.
| Kriterya | InheritedWidget | Callback |
|---|---|---|
| Direksyon | Mula sa itaas pababa (parent → mga inapo) | Mula sa ibaba pataas (child → parent) o direkta |
| Saklaw | Buong sub-tree | Tiyak na widget |
| Muling pagtatayo | Awtomatiko kapag nagbago ang data | Nangangailangan ng manu-manong setState |
| Kompleksidad | Katamtaman (kailangan ng klase ng InheritedWidget) | Mababa (simpleng function) |
Provider at Riverpod — mga sikat na library ng pamamahala ng estado sa Flutter, na binuo sa ibabaw ng InheritedWidget. Pinapalawak nila ang mga kakayahan nito: nagdaragdag ng suporta para sa ChangeNotifier, awtomatikong pag-alis kapag na-disassemble, lazy initialization at pinasimpleng syntax sa pamamagitan ng generics.
Provider ay gumagamit ng InheritedWidget upang magpadala ng object ng anumang uri pababa sa puno. Ang ChangeNotifierProvider ay sumusubaybay ng mga pagbabago sa pamamagitan ng ChangeNotifier at tumatawag ng updateShouldNotify kapag tinawag ang notifyListeners. Ito ay nagpapalaya sa developer mula sa manu-manong paglikha ng InheritedWidget at pagpapatupad ng updateShouldNotify.
Ang direktang InheritedWidget ay nagbibigay ng higit na kontrol at hindi nangangailangan ng mga panlabas na dependency. Ang Provider ay nagbibigay ng handa na imprastraktura: Consumer, Selector, MultiProvider, ProxyProvider. Ang pagpili ay depende sa kompleksidad ng app. Para sa mga simpleng proyekto, sapat na ang direktang InheritedWidget; para sa malalaking proyekto, ang Provider o Riverpod ay nagbabawas ng template code.
// Direktang 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 katumbas
return ChangeNotifierProvider<UserData>(
create: (_) => UserData(),
child: MyApp(),
);
Ang parehong diskarte sa halimbawa ay lumulutas ng parehong gawain — pagpapadala ng UserData pababa sa puno. Provider ay nagbabawas ng dami ng code ngunit itinatago ang mekanika ng InheritedWidget. Ang direktang InheritedWidget ay nagbibigay ng buong kontrol at pag-unawa sa nangyayari, na lalong mahalaga kapag nag-aaral ng Flutter at nagde-debug ng mga kumplikadong problema sa muling pagtatayo.
Mga Madalas Itanong
InheritedWidget ay ginagawang accessible ang data sa lahat ng mga inapo sa pamamagitan ng BuildContext, habang ang ordinaryong widget ay nagpapadala lamang ng data sa pamamagitan ng konstruktor. Ang InheritedWidget ay nag-subscribe rin ng mga inapo sa mga update ng data.
Ang mga umaasang widget ay muling itinatayo lamang kapag ang updateShouldNotify ay nagbalik ng true. Kung ang paraan ay naipatupad nang tama, ang muling pagtatayo ay nangyayari lamang kapag talagang nagbago ang data, hindi sa bawat rebuild ng parent.
Oo, maaari kang gumamit ng anumang bilang ng InheritedWidget sa iisang puno. Bawat isa ay nagbibigay ng data ng isang partikular na uri, at ang mga widget ay maaaring makatanggap ng data mula sa maraming InheritedWidget nang sabay-sabay.
dependOn ay nag-subscribe ng widget sa mga update — kapag nagbago ang data, ang widget ay muling itatayo. findAncestor ay nagsasagawa ng isang beses na paghahanap nang walang subscription, at ang widget ay hindi malalaman ang tungkol sa mga pagbabago ng data.
Para sa simpleng estado (tema, mga setting) sapat na ang InheritedWidget. Para sa kumplikadong estado na may business logic, gamitin ang Provider, Riverpod o BLoC — sila ay binuo sa ibabaw ng InheritedWidget at nagdaragdag ng kinakailangang imprastraktura.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din