← Назад к вопросам

Можно ли подписаться на обновления InheritedWiget в initState?

1.8 Middle🔥 191 комментариев
#Flutter виджеты#State Management

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Подписка на InheritedWidget в initState

Короткий ответ: Нет, нельзя напрямую в initState, но есть способы это сделать правильно.

Разберёмся почему и как правильно обработать обновления InheritedWidget.

Почему нельзя в initState?

Проблема 1: InheritedWidget требует BuildContext

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  @override
  void initState() {
    super.initState();
    
    // Это не работает! BuildContext ещё не готов
    final value = context.watch<MyInheritedWidget>();
    // Error: context не может быть использован в initState
  }
}

Проблема 2: initState вызывается только один раз

Esли InheritedWidget обновится, подписка в initState не отреагирует.

Способ 1: Использовать didChangeDependencies (правильный)

Этот метод вызывается, когда widget зависит от другого widget'а:

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late String _inheritedValue;
  
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    
    // Это работает! Context полностью инициализирован
    final inheritedWidget = 
        context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
    _inheritedValue = inheritedWidget?.value ?? 'default';
  }
  
  @override
  Widget build(BuildContext context) {
    return Text(_inheritedValue);
  }
}

Преимущества:

  • Вызывается в правильный момент жизненного цикла
  • Вызывается каждый раз при обновлении зависимостей
  • context полностью инициализирован

Способ 2: Использовать Provider пакет (рекомендуемый)

Это более современный и удобный подход:

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late String _value;
  
  @override
  void initState() {
    super.initState();
    
    // После build, в FrameworkBinding микротаске
    Future.microtask(() {
      final value = context.read<MyProvider>();
      setState(() {
        _value = value;
      });
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Consumer<MyProvider>(
      builder: (context, provider, child) {
        return Text(provider.value);
      },
    );
  }
}

Способ 3: Обновлять в build() методе

Для простых случаев можно просто читать значение в build():

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  @override
  Widget build(BuildContext context) {
    // Это работает и обновляется автоматически
    final inheritedValue = 
        context.watch<MyInheritedWidget>();
    
    return Text(inheritedValue.value);
  }
}

Полный пример с InheritedWidget

// 1. Создаём InheritedWidget
class MyInheritedWidget extends InheritedWidget {
  final String value;
  final Widget child;
  
  MyInheritedWidget({
    required this.value,
    required this.child,
  }) : super(child: child);
  
  static MyInheritedWidget of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>()
        ?? MyInheritedWidget(value: 'default', child: Container());
  }
  
  @override
  bool updateShouldNotify(MyInheritedWidget oldWidget) {
    return oldWidget.value != value;
  }
}

// 2. Используем в StatefulWidget
class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    final inherited = MyInheritedWidget.of(context);
    print('InheritedWidget updated: ${inherited.value}');
  }
  
  @override
  Widget build(BuildContext context) {
    final inherited = MyInheritedWidget.of(context);
    return Text(inherited.value);
  }
}

Способ 4: Использовать Future.microtask в initState

Это hacky, но работает:

@override
void initState() {
  super.initState();
  
  // После первого build
  Future.microtask(() {
    final inherited = context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
    setState(() {
      _myValue = inherited?.value ?? 'default';
    });
  });
}

Сравнение подходов

СпособКогда использоватьМинусы
didChangeDependenciesОсновной способВызывается часто
build + watchПростые случаиКаждый build перестраивает
Future.microtaskНужны инициализирующие данныеHacky, нелогично
Provider пакетСовременные проектыЗависимость от пакета

Best Practice

Используй didChangeDependencies для подписки на InheritedWidget:

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  
  // Читать значение при изменении зависимостей
  _value = context.dependOnInheritedWidgetOfExactType<MyInherited>()??.value ?? 'default';
}

Это правильное место в жизненном цикле для подписки на изменения InheritedWidget.