Проблема пов’язана з вашою пропозицією, яка є неправильною.
Як ви вже сказали, InheritedWidgets, як і інші віджети, незмінні. Тому вони не оновлюються . Вони створюються заново.
Річ у тому, що InheritedWidget - це просто простий віджет, який не робить нічого, крім зберігання даних . Він не має жодної логіки оновлення чи чогось іншого. Але, як і будь-які інші віджети, він пов'язаний із Element
. І вгадайте, що? Цю річ можна змінювати, і тріпотіння буде використовувати її по можливості, коли це можливо!
Виправлена цитата буде такою:
InheritedWidget, якщо посилання здійснюється таким чином, призведе до відновлення споживача при зміні InheritedWidget, пов’язаного з InheritedElement .
Існує чудова розмова про те, як віджети / елементи / візуалізатор підключаються . Але коротше, вони такі (зліва - це типовий віджет, посередині - "елементи", а праворуч - "візуалізатори"):
Справа в тому, що коли ви створюєте інстанцію нового віджета; флаттер порівняє його зі старим. Повторно використовуйте його "Елемент", який вказує на RenderBox. І змінити властивості RenderBox.
Гаразд, але як це відповідає на моє запитання?
При створенні екземпляра InheritedWidget, а потім виклику context.inheritedWidgetOfExactType
(або MyClass.of
який в основному однаковий); мається на увазі, що він буде слухати Element
асоційований з вами InheritedWidget
. І щоразу, коли це Element
отримує новий віджет, він примушує оновити будь-які віджети, які викликали попередній метод.
Коротше кажучи, коли ви замінюєте існуюче InheritedWidget
на нове; трепет побачить, що він змінився. І повідомить пов’язані віджети про можливу модифікацію.
Якщо ви все зрозуміли, ви вже мали здогадатися про рішення:
Загорніть InheritedWidget
всередину щось, StatefulWidget
що створить абсолютно нове, InheritedWidget
коли б щось змінилося!
Кінцевим результатом у фактичному коді буде:
class MyInherited extends StatefulWidget {
static MyInheritedData of(BuildContext context) =>
context.inheritFromWidgetOfExactType(MyInheritedData) as MyInheritedData;
const MyInherited({Key key, this.child}) : super(key: key);
final Widget child;
@override
_MyInheritedState createState() => _MyInheritedState();
}
class _MyInheritedState extends State<MyInherited> {
String myField;
void onMyFieldChange(String newValue) {
setState(() {
myField = newValue;
});
}
@override
Widget build(BuildContext context) {
return MyInheritedData(
myField: myField,
onMyFieldChange: onMyFieldChange,
child: widget.child,
);
}
}
class MyInheritedData extends InheritedWidget {
final String myField;
final ValueChanged<String> onMyFieldChange;
MyInheritedData({
Key key,
this.myField,
this.onMyFieldChange,
Widget child,
}) : super(key: key, child: child);
static MyInheritedData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyInheritedData>();
}
@override
bool updateShouldNotify(MyInheritedData oldWidget) {
return oldWidget.myField != myField ||
oldWidget.onMyFieldChange != onMyFieldChange;
}
}
Але чи не створить новий InheritedWidget відновлення цілого дерева?
Ні, це не обов’язково. Оскільки ваш новий InheritedWidget потенційно може мати точно таку ж дочірню історію, як і раніше. І точно кажучи, я маю на увазі той самий екземпляр. Віджети, які мають той самий екземпляр, що був раніше, не відновлюються.
І в більшості ситуацій (маючи спадковий віджет у корені програми) успадкований віджет є постійним . Тож ніякої непотрібної перебудови.