Блок Flutter: не удалось найти предка, начиная с контекста?

#flutter

#flutter

Вопрос:

Я новичок в Flutter, а также в использовании блоков.

У меня ошибка при компиляции кода:

     The following assertion was thrown building Login(dirty, state: _LoginFormState#44e7f):
         BlocProvider.of() called with a context that does not contain a Bloc of type BtnBloc.
         No ancestor could be found starting from the context that was passed to
         BlocProvider.of<BtnBloc>().
       This can happen if the context you use comes from a widget above the BlocProvider.
         This can also happen if you used BlocProviderTree and didn't explicity provide 
         the BlocProvider types: BlocProvider(bloc: BtnBloc()) instead of BlocProvider<BtnBloc>(bloc:
         BtnBloc()).
         The context used was: Login(dirty, state: _LoginFormState#44e7f)    
  

Я пытался изменить некоторые вещи в моем классе bloc, но ничего не получается.

Вот мой класс blog :

 class BtnBloc extends Bloc<BtnEvent, BtnState> {
  @override
  BtnState get initialState => BtnState.initial();

  @override
  Stream<BtnState> mapEventToState(
      BtnState currentState, BtnEvent event) async* {
    if (event is IdleEvent) {
      yield currentState..state = 1;
    } else if (event is LoadingEvent) {
      yield currentState..state = 1;
    } else if (event is RevealEvent) {
      yield currentState..state = 2;
    }
  }
}
  

И вот мой метод сборки :

 final _btnBloc = new BtnBloc();

  _LoginFormState(
      {Key key,
      this.primaryColor,
      this.backgroundColor,
      this.backgroundImage,
      this.logo});

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
        bloc: _btnBloc,
        child: BlocBuilder<BtnEvent, BtnState>(
            bloc: BlocProvider.of<BtnBloc>(context),
            builder: (context, BtnState state) {
return myWidget();
  

Пожалуйста, помогите мне:'(

Ответ №1:

Я надеюсь, что по прошествии некоторого времени, столкнувшись с этой проблемой, эта статья поможет вам лучше понять context . Общее решение такое же, как ответ @Filled Stacks. Это означает, что вы должны передать блок при переходе на новую страницу, чтобы BlocProvider можно было определить, какой тип блока вы получите.

Я рекомендую запустить функцию main для общего приложения, которая инициализирует ваши экраны и контекст через экраны. Например:

  • Инициализация и блок передачи:
 class ListTodoPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<TodoBloc>(
        create: (context) => TodoBloc(TodoDao())..add(QueryTodoEvent()),
        child: ListTodoPageful());
  }
}

class ListTodoPageful extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return ListTodoState();
  }
}

class ListTodoState extends State<ListTodoPageful> {
  TodoBloc _todoBloc;
  @override
  Widget build(BuildContext context) {
    _todoBloc = BlocProvider.of<TodoBloc>(
        context);
   //...
   floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
              context,
              CupertinoPageRoute(
                  builder: (context) => BlocProvider.value(
                      value: _todoBloc, child: CreateTaskPage())));
        }
  //...
}
  
  • Блок приема:
 class _CreatePageState extends State<CreateTaskPage> {
  TodoBloc _todoBloc;

  @override
  Widget build(BuildContext context) {
    _todoBloc = BlocProvider.of<TodoBloc>(context);
}
  

Обратитесь к моему образцу приложения здесь: https://github.com/huynguyennovem/flutter_todo

Ответ №2:

Строка ниже — ваша проблема. Ошибка — это именно то, о чем говорится в сообщении.

 ...
child: BlocBuilder<BtnEvent, BtnState>(
     bloc: BlocProvider.of<BtnBloc>(context), <------- Problem line
     builder: (context, BtnState state) {
...
  

К контексту, который вы там используете, не привязан Blockbuilder, поэтому ничто не передает блок сверху вниз в ваше loginState. Вы можете либо

  1. Используйте свой существующий блок (_btnBloc) и передайте его (рекомендуется)
  2. Оберните виджет, выводящий loginState на экран, с помощью BlocProvider, чтобы у вас был доступ к нему в состоянии виджета.

Если это ваш первый просмотр, тогда используйте 1.

Изменить

  bloc: BlocProvider.of<BtnBloc>(context), <------- Problem line
  

Для

 bloc: _btnBloc
  

Комментарии:

1. @VincentGuillois Рад, что помог.