Ответ
InheritedWidget — это специальный виджет в Flutter, предназначенный для эффективной передачи данных вниз по дереву виджетов. Он позволяет дочерним виджетам получать доступ к данным без необходимости явно прокидывать их через конструкторы каждого промежуточного виджета (проброс пропсов).
Ключевые особенности:
- Эффективность: При изменении данных в
InheritedWidgetFlutter перестраивает только те виджеты, которые от этих данных зависят (вызвалиcontext.dependOnInheritedWidgetOfExactType), а не всё поддерево. - Доступность: Любой виджет в поддереве ниже
InheritedWidgetможет получить к нему доступ. - Использование: Исторически использовался для тем, локализации, аутентификации или любого другого «глобального» для поддерева состояния.
Пример реализации и использования:
// 1. Создаем InheritedWidget
class AppTheme extends InheritedWidget {
final Color primaryColor;
final Brightness brightness;
const AppTheme({
required this.primaryColor,
required this.brightness,
required Widget child,
Key? key,
}) : super(key: key, child: child);
// 2. Статический метод для удобного доступа
static AppTheme of(BuildContext context) {
final AppTheme? result = context.dependOnInheritedWidgetOfExactType<AppTheme>();
assert(result != null, 'No AppTheme found in context');
return result!;
}
// 3. Метод, определяющий, нужно ли уведомлять зависимые виджеты об обновлении
@override
bool updateShouldNotify(AppTheme oldWidget) {
return primaryColor != oldWidget.primaryColor || brightness != oldWidget.brightness;
}
}
// 4. Использование в дочернем виджете
class ThemedButton extends StatelessWidget {
const ThemedButton({super.key});
@override
Widget build(BuildContext context) {
// Получаем данные из ближайшего AppTheme в дереве
final theme = AppTheme.of(context);
return ElevatedButton(
style: ElevatedButton.styleFrom(primary: theme.primaryColor),
onPressed: () {},
child: const Text('Кнопка'),
);
}
}
Важно: InheritedWidget — это низкоуровневый примитив. В современных приложениях для управления состоянием чаще используются пакеты-надстройки, такие как Provider (который сам построен на InheritedWidget), Riverpod или Bloc, так как они предоставляют более удобный API и лучшие возможности для тестирования.
Ответ 18+ 🔞
Э, слушай, вот есть в Flutter'е такая штука — InheritedWidget. Представь себе, что ты пытаешься передать бутылку воды через всю толпу на концерте, а вокруг тебя — овердохуища народу. Так вот, InheritedWidget — это как будто ты ставишь эту бутылку на сцену и кричишь: «Кому надо — берите!». Любой в зале может до неё дотянуться, не передавая из рук в руки через десять человек.
В чём прикол:
- Не жрёт ресурсы: Когда данные в этом виджете меняются, Flutter не начинает долбить и пересобирать всё подряд. Он умный — обновляет только тех, кто реально завис от этих данных и сказал «я на них подписан». Остальным — да похуй, они и так работают.
- Доступ — раз плюнуть: Любой виджет-потомок может в любой момент закричать «эй, дай сюда тему!» и получить её. Никаких пробросов через десять конструкторов, где в каждом промежуточном виджете ты пишешь
final Color someColorи чувствуешь себя идиотом. - Классика жанра: Раньше это был главный способ тащить темы, настройки языка или данные юзера куда угодно. Честно, иногда и сейчас удобно, если проект не огромный.
Смотри, как это выглядит на практике:
// 1. Делаем своего наследничка
class AppTheme extends InheritedWidget {
final Color primaryColor;
final Brightness brightness;
const AppTheme({
required this.primaryColor,
required this.brightness,
required Widget child,
Key? key,
}) : super(key: key, child: child);
// 2. Делаем статический метод, чтобы было удобно орать "Дай тему!"
static AppTheme of(BuildContext context) {
// Вот эта строка — магия. Она говорит: "Ищи выше по дереву AppTheme и подпишись на него".
final AppTheme? result = context.dependOnInheritedWidgetOfExactType<AppTheme>();
// На всякий случай орём, если не нашли (но обычно находим).
assert(result != null, 'No AppTheme found in context');
return result!;
}
// 3. Самое важное! Тут решаем, пора ли будить всех подписчиков.
@override
bool updateShouldNotify(AppTheme oldWidget) {
// Если цвет или яркость поменялись — да, пора орать "Обновитесь!".
return primaryColor != oldWidget.primaryColor || brightness != oldWidget.brightness;
}
}
// 4. Используем где угодно внизу по дереву
class ThemedButton extends StatelessWidget {
const ThemedButton({super.key});
@override
Widget build(BuildContext context) {
// Вжух! И тема у нас в кармане. Никаких пробросов.
final theme = AppTheme.of(context);
return ElevatedButton(
style: ElevatedButton.styleFrom(primary: theme.primaryColor),
onPressed: () {},
child: const Text('Кнопка'),
);
}
}
Но есть нюанс, ёпта! InheritedWidget — это как голый двигатель. Мощно, но возиться с ним — терпения ноль ебать. Поэтому сейчас все умные люди берут готовые обёртки: Provider (который внутри — тот же самый InheritedWidget, но с конфеткой), Riverpod или Bloc. Они дают меньше мороки и меньше шансов выстрелить себе в ногу. Но знать, как работает этот костыль в основе — полезно, а то будешь как мартышлюшка, которая кнопки тыкает, не понимая, что внутри.