Как правильно использовать InheritedWidget? Пока я понял, что это дает вам возможность распространять данные по дереву виджетов. В крайнем случае, если вы установите это как RootWidget, он будет доступен из всех виджетов в дереве на всех маршрутах, что нормально, потому что каким-то образом мне нужно сделать свою ViewModel / модель доступной для моих виджетов без необходимости прибегать к глобальным или синглетонам.
НО InheritedWidget неизменяем, так как я могу его обновить? И что еще более важно, как мои виджеты с отслеживанием состояния запускаются для восстановления своих поддеревьев?
К сожалению, документация здесь очень неясна, и после многих обсуждений никто, кажется, действительно не знает, как ее правильно использовать.
Я добавляю цитату Брайана Игана:
Да, я рассматриваю это как способ распространения данных по дереву. Что меня смущает из документации API:
«Унаследованные виджеты, когда на них ссылаются таким образом, заставят потребителя перестраивать, когда сам унаследованный виджет изменяет состояние».
Когда я впервые прочитал это, я подумал:
Я мог бы поместить некоторые данные в InheritedWidget и изменить их позже. Когда произойдет эта мутация, он перестроит все виджеты, которые ссылаются на мой InheritedWidget. Что я нашел:
Чтобы изменить состояние InheritedWidget, вам необходимо обернуть его в StatefulWidget. Затем вы фактически мутируете состояние StatefulWidget и передаете эти данные в InheritedWidget, который передает данные всем своим дочерним элементам. Однако в этом случае, кажется, перестраивается все дерево под StatefulWidget, а не только виджеты, которые ссылаются на InheritedWidget. Это правильно? Или он каким-то образом знает, как пропустить виджеты, которые ссылаются на InheritedWidget, если updateShouldNotify возвращает false?
источник
MyInherited.of(context)
.updateShouldNotify
тест всегда относится к одному и тому жеMyInheritedState
экземпляру, не всегдаfalse
ли он возвращается ? Конечно,build
методMyInheritedState
создания новых_MyInherited
экземпляров, ноdata
поле всегда ссылается наthis
нет? У меня проблемы ... Работает, если я просто кодируюtrue
.TL; DR
Не используйте тяжелые вычисления внутри метода updateShouldNotify и используйте const вместо new при создании виджета
Прежде всего, мы должны понять, что такое объекты Widget, Element и Render.
Теперь мы готовы погрузиться в InheritedWidget и метод BuildContext inheritFromWidgetOfExactType .
В качестве примера я рекомендую рассмотреть этот пример из документации Flutter о InheritedWidget:
InheritedWidget - просто виджет, реализующий в нашем случае один важный метод - updateShouldNotify . updateShouldNotify - функция, которая принимает один параметр oldWidget и возвращает логическое значение: true или false.
Как и любой виджет, InheritedWidget имеет соответствующий объект Element. Это InheritedElement . InheritedElement вызывает updateShouldNotify для виджета каждый раз, когда мы создаем новый виджет (вызываем setState для предка). Когда updateShouldNotify возвращает true, InheritedElement выполняет итерацию по зависимостям (?) И вызывает для него метод didChangeDependencies .
Откуда InheritedElement получает зависимости ? Здесь мы должны посмотреть на метод inheritFromWidgetOfExactType .
inheritFromWidgetOfExactType - этот метод определен в BuildContext, и каждый элемент реализует интерфейс BuildContext (Element == BuildContext). Итак, у каждого элемента есть этот метод.
Давайте посмотрим на код inheritFromWidgetOfExactType:
Здесь мы пытаемся найти предка в _inheritedWidgets, отображаемом по типу. Если предок найден, мы вызываем inheritFromElement .
Код для inheritFromElement :
Итак, теперь мы знаем, где InheritedElement получает свои зависимости.
Теперь давайте посмотрим на метод didChangeDependencies . У каждого элемента есть этот метод:
Как мы видим, этот метод просто отмечает элемент как грязный, и этот элемент должен быть перестроен в следующем кадре. Перестройка означает построение метода вызова на соответствующем элементе виджета.
Но как насчет «Все поддерево перестраивается, когда я перестраиваю InheritedWidget?». Здесь мы должны помнить, что виджеты неизменяемы, и если вы создадите новый виджет, Flutter перестроит поддерево. Как это исправить?
источник
Из документов :
Как отмечалось в OP,
InheritedWidget
экземпляр не меняется ... но его можно заменить новым экземпляром в том же месте в дереве виджетов. Когда это произойдет, возможно, потребуется перестроить зарегистрированные виджеты.InheritedWidget.updateShouldNotify
Метод делает это определение. (См .: документы )Итак, как можно заменить экземпляр?
InheritedWidget
Экземпляр может быть , удерживаемыйStatefulWidget
, который может заменить старый экземпляр с новым экземпляром.источник
InheritedWidget управляет централизованными данными приложения и передает их потомку, как будто мы можем хранить здесь количество корзин, как описано здесь :
источник