InheritedWidget, Flutter'da yapıcılar aracılığıyla açıkça iletmeden widget ağacında aşağıya doğru veri aktaran özel bir widget'tır. Alt widget'lar BuildContext aracılığıyla verilere erişir ve otomatik olarak güncellemelere abone olur. InheritedWidget'daki veriler değiştiğinde, bağımlı tüm widget'lar yeniden oluşturulur. Flutter API Reference, 2025'e göre InheritedWidget, Theme, MediaQuery, Localizations ve çoğu durum yönetimi kütüphanesinin temelidir.
Önemli Noktalar
InheritedWidget, verilerini Widget Tree'deki tüm torunlar için kullanılabilir hale getiren bir widget'tır. Verileri yalnızca yapıcılar aracılığıyla alt öğelere aktaran normal bir widget'ın aksine, InheritedWidget, alt ağaçtaki herhangi bir widget'ın parametre zinciri olmadan verilere erişmesine izin verir. Bu, “prop drilling” sorununu çözer — bu verileri kendileri kullanmayan birçok ara widget üzerinden veri aktarma.
Flutter birkaç yerleşik InheritedWidget içerir: Theme (renk şeması ve stiller), MediaQuery (ekran boyutu, yönlendirme, piksel yoğunluğu), Localizations (yerelleştirilmiş dizeler), Directionality (metin yönü), DefaultTextStyle (varsayılan metin stili). Bu widget'lar MaterialApp gibi kök widget'lar tarafından ayarlanır ve uygulama genelinde kullanılabilir.
InheritedWidget'ın kendi durumu yoktur — yapıcı aracılığıyla aktarılan verileri depolar. InheritedWidget'ın ebeveyni yeni verilerle yeniden oluşturulduğunda, eski ve yeni verileri karşılaştırmak için updateShouldNotify yöntemi çağrılır. Yöntem true döndürürse, bağımlı tüm widget'lar yeniden oluşturma için işaretlenir. Bu basit ama etkili bir reaktif güncelleme mekanizmasıdır.
InheritedWidget üzerinden veri aktarım mekanizması Element Tree'ye dayanır. Bir widget dependOnInheritedWidgetOfExactType'ı çağırdığında, ilgili öğe InheritedElement üzerinde bir bağımlılık kaydeder. InheritedWidget değiştiğinde, InheritedElement bağımlı tüm öğeleri bildirir ve bunlar sonraki karede yeniden oluşturulur.
dependOnInheritedWidgetOfExactType yöntemi yalnızca ağaçta InheritedWidget'ı bulmakla kalmaz — geçerli öğeyi bildirimlere abone yapar. dependOn yerine findAncestorWidgetOfExactType kullanırsanız, widget verileri alır ancak değiştiğinde yeniden oluşturulmaz. Bu önemli bir farktır: dependOn bir aboneliktir, findAncestor tek seferlik bir aramadır.
Bir widget InheritedWidget istediğinde, Flutter geçerli öğeden köke kadar Element Tree'de yukarı çıkar ve her InheritedElement'i tür eşleşmesi için kontrol eder. Eşleşen ilk InheritedElement döndürülür. Bu, ağaçtaki en yakın InheritedWidget'ın önceliğe sahip olduğu anlamına gelir — InheritedWidget'ı torunlara daha yakın yerleştirerek belirli bir seviyede verileri geçersiz kılabilirsiniz.
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;
}
Bu örnekte, MyTheme torunlara veri sağlamak için statik bir of yöntemi kullanır. dependOnInheritedWidgetOfExactType yöntemi bir bağımlılık kaydeder ve updateShouldNotify, bağımlı widget'ların yeniden oluşturulması gerekip gerekmediğini belirlemek için eski ve yeni verileri karşılaştırır.
Özel InheritedWidget oluşturma iki adımdan oluşur: InheritedWidget'ı genişleten bir sınıf tanımlama ve torunlardan erişim için statik bir of yöntemi uygulama. Veriler yapıcı aracılığıyla aktarılır ve updateShouldNotify yöntemi, bağımlı widget'ların ne zaman yeniden oluşturulması gerektiğini belirler.
Sınıf InheritedWidget'ı genişletmeli ve zorunlu child parametresi olan bir yapıcı aracılığıyla verileri kabul etmelidir. Veriler herhangi bir türde olabilir: ilkeller, nesneler, işlevler. Ana kural, eski ve yeni değerlerin güvenilir bir şekilde karşılaştırılabilmesi için verilerin değişmez (immutable) olması gerektiğidir.
Statik of yöntemi BuildContext alır ve InheritedWidget verilerini döndürür. İçte, ağaçta belirtilen türdeki en yakın InheritedWidget'ı bulan dependOnInheritedWidgetOfExactType'ı çağırır. InheritedWidget bulunamazsa, yöntem uygulamaya bağlı olarak bir istisna fırlatır veya varsayılan bir değer döndürür.
Verilere erişmek için widget, build yöntemi içinde MyWidget.of(context) çağrısı yapar. Flutter otomatik olarak widget'ı güncellemelere abone yapar. Veriler değişirse, widget sonraki karede yeniden oluşturulur. Bu, gereksiz parametreler olmadan temiz ve bildirimsel kod sağlar.
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;
}
Bu örnekte, UserPreferences kullanıcı ayarlarını saklar. updateShouldNotify yöntemi her alanı ayrı ayrı karşılaştırır, bu da yalnızca bir parametre değiştiğinde gereksiz yeniden oluşturmaları önler. Birden çok alanı olan kendi InheritedWidget'larınız için benzer bir yaklaşım kullanın.
updateShouldNotify, bağımlı widget'ların veri değişiklikleri hakkında bilgilendirilmesi gerekip gerekmediğini belirleyen InheritedWidget'ın ana yöntemidir. Yöntem false döndürürse, InheritedWidget'ın kendisi aynı verilerle yeni bir örnek alsa bile bağımlı widget'lar yeniden oluşturulmaz. Bu, performans için kritik derecede önemlidir.
Yalnızca gerçekten değişen ve görüntülemeyi etkileyen alanları karşılaştırın. InheritedWidget 10 alan içeriyorsa ancak yalnızca biri kullanıcı arayüzünü etkiliyorsa, yalnızca o alanı kontrol edin. Koleksiyonlar için derin karşılaştırma veya değişmez veri yapıları kullanın. Liste veya Harita için == kullanmayın, çünkü referansa göre karşılaştırma yaparlar.
En yaygın hata, karşılaştırma olmadan true döndürmektir. Bu, veriler değişmemiş olsa bile tüm bağımlı widget'ların her ebeveyn güncellemesinde yeniden oluşturulmasına neden olur. İkinci hata, veriler değiştiğinde false döndürmektir, bu da güncel olmayan bir kullanıcı arayüzüne yol açar. Üçüncüsü, her karede çalışan ve performansı yavaşlatan karmaşık karşılaştırmadır.
InheritedWidget ve geri çağrımlar (yapıcılar aracılığıyla işlev aktarma) farklı sorunları çözer. InheritedWidget, ağacın farklı seviyelerinde birçok widget tarafından ihtiyaç duyulan veriler için uygundur. Geri çağrımlar, ebeveynden belirli bir alt öğeye veya tam tersi yönde tek yönlü olay aktarımı için kullanışlıdır. Seçim, uygulama mimarisine ve güncelleme sıklığına bağlıdır.
Farklı iç içe geçme seviyelerinde birçok widget tarafından veriye ihtiyaç duyulduğunda InheritedWidget kullanın: uygulama teması, kullanıcı ayarları, cihaz bilgileri, mevcut oturum verileri. InheritedWidget özellikle nadiren değişen ancak kullanıcı arayüzünün farklı bölümlerinde ihtiyaç duyulan “küresel” veriler için etkilidir.
Geri çağrımlar (callback işlevleri), bir alt widget'tan ebeveyne olay aktarmak için uygundur: düğmeye basma, liste öğesi seçimi, form gönderme. Geri çağrımlar, bir alt öğenin hangi eylemleri gerçekleştirebileceğini açıkça belirtir ve gizli bağımlılıklar oluşturmaz. Az sayıda seviye üzerinden ağaçta aşağıya doğru veri aktarmak için yapıcı parametrelerini kullanmak da daha basittir.
| Kriter | InheritedWidget | Geri Çağrımlar |
|---|---|---|
| Yön | Yukarıdan aşağıya (ebeveyn → torunlar) | Aşağıdan yukarıya (alt → ebeveyn) veya doğrudan |
| Kapsam | Tüm alt ağaç | Belirli widget |
| Yeniden Oluşturma | Veri değişiminde otomatik | Manuel setState gerektirir |
| Karmaşıklık | Orta (InheritedWidget sınıfı gerekir) | Düşük (sadece bir işlev) |
Provider ve Riverpod, InheritedWidget üzerine inşa edilmiş Flutter'daki popüler durum yönetimi kütüphaneleridir. Yeteneklerini genişletirler: ChangeNotifier desteği, çıkarma sırasında otomatik temizleme, tembel başlatma ve jeneriklerle basitleştirilmiş sözdizimi eklerler.
Provider, herhangi bir türdeki nesneyi ağaçta aşağıya aktarmak için InheritedWidget kullanır. ChangeNotifierProvider, ChangeNotifier aracılığıyla değişiklikleri izler ve notifyListeners çağrıldığında updateShouldNotify'ı çağırır. Bu, geliştiriciyi manuel olarak InheritedWidget oluşturmaktan ve updateShouldNotify uygulamaktan kurtarır.
Doğrudan InheritedWidget daha fazla kontrol sağlar ve harici bağımlılıklar gerektirmez. Provider hazır altyapı sağlar: Consumer, Selector, MultiProvider, ProxyProvider. Seçim, uygulama karmaşıklığına bağlıdır. Basit projeler için doğrudan InheritedWidget yeterlidir; büyük projeler için Provider veya Riverpod kalıplaşmış kodu azaltır.
// Doğrudan 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 eşdeğeri
return ChangeNotifierProvider<UserData>(
create: (_) => UserData(),
child: MyApp(),
);
Örnekteki her iki yaklaşım da aynı sorunu çözer — UserData'yı ağaçta aşağıya aktarma. Provider kod hacmini azaltır ancak InheritedWidget mekaniğini gizler. Doğrudan InheritedWidget tam kontrol ve neler olup bittiğini anlama sağlar, bu özellikle Flutter öğrenirken ve karmaşık yeniden oluşturma sorunlarını hata ayıklarken önemlidir.
Sıkça Sorulan Sorular
InheritedWidget BuildContext aracılığıyla tüm torunlar için verileri kullanılabilir hale getirirken, normal bir widget yalnızca yapıcı aracılığıyla veri aktarır. InheritedWidget ayrıca torunları veri güncellemelerine abone yapar.
Bağımlı widget'lar yalnızca updateShouldNotify true döndürdüğünde yeniden oluşturulur. Yöntem doğru uygulanırsa, yeniden oluşturma yalnızca veriler gerçekten değiştiğinde gerçekleşir, her ebeveyn yeniden oluşturmasında değil.
Evet, aynı ağaçta herhangi bir sayıda InheritedWidget kullanabilirsiniz. Her biri belirli bir türde veri sağlar ve widget'lar aynı anda birden çok InheritedWidget'dan veri alabilir.
dependOn widget'ı güncellemelere abone yapar — veri değiştiğinde widget yeniden oluşturulur. findAncestor abonelik olmadan tek seferlik arama yapar ve widget veri değişikliklerinden haberdar olmaz.
Basit durum (tema, ayarlar) için InheritedWidget yeterlidir. İş mantığı olan karmaşık durum için Provider, Riverpod veya BLoC kullanın — bunlar InheritedWidget üzerine inşa edilmiştir ve gerekli altyapıyı ekler.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun