Как разделить блок между контекстами - PullRequest
1 голос
/ 30 марта 2019

Я пытаюсь получить доступ к экземпляру блока, созданному в корне моего приложения после перехода в новый контекст с помощью showDialog(). Однако, если я пытаюсь получить блок, как обычно, получая его из контекста, например _thisBlocInstance = BlocProvider.of<ThisBlocType>(context), я получаю ошибку, которая указывает, что в этом контексте блок не предусмотрен.

Я предполагаю, что это потому, что метод showDialog() назначает новый контекст виджетам в диалоговом окне, которые не знают о блоке, который я пытаюсь найти, который был создан, как только пользователь входит в систему:

  @override
Widget build(BuildContext context) {
  _authBloc = BlocProvider.of<AuthBloc>(context);
  _accountBloc = AccountBloc(authBloc: _authBloc);

  return BlocProvider(
    bloc: _accountBloc,

 ....

В углу есть кнопка, которая отображает диалоговое окно:

@override
Widget build(BuildContext context) {
  return Align(
    alignment: Alignment.bottomRight,
    child: Padding(
      padding: const EdgeInsets.all(18.0),
      child: FloatingActionButton(
        onPressed: () => showDialog(
          context: context,
          builder: (newContext) => EventDialog(),
        ).then(
          (val) => print(val)
        ),
        child: Icon(Icons.add),
      ),
    ),
  );
}

А в EventDialog я снова пытаюсь найти блок с контекстом:

@override
void build(BuildContext context) {

  _accountBloc = BlocProvider.of<AccountBloc>(context);
  _userMenuItems = _accountBloc.usersInAccount
    .map((user) => DropdownMenuItem(
          child: Text(user.userName),
          value: user.userId,
        ))
    .toList();
}

И это терпит неудачу, с ошибкой «блок getter был вызван в null», или нет блока этого типа, привязанного к этому контексту.

Есть ли какой-нибудь способ получить доступ к блоку только из контекста после использования showDialog () или иным образом перехода в новый контекст?

Это класс провайдера блока:

import 'package:flutter/material.dart';

//This class is a generic bloc provider from https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc/
//it allows easy access to the blocs by ancestor widgets and handles calling their dispose method

class BlocProvider<T extends BlocBase> extends StatefulWidget {
  BlocProvider({
    Key key,
    @required this.child,
    @required this.bloc,
  }): super(key: key);

  final T bloc;
  final Widget child;

  @override
  _BlocProviderState<T> createState() => _BlocProviderState<T>();

  static T of<T extends BlocBase>(BuildContext context){
    final type = _typeOf<BlocProvider<T>>();
    BlocProvider<T> provider = context.ancestorWidgetOfExactType(type);
    return provider.bloc;
  }

  static Type _typeOf<T>() => T;
}

class _BlocProviderState<T> extends State<BlocProvider<BlocBase>>{
  @override
  void dispose(){
    widget.bloc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context){
    return widget.child;
  }
}

abstract class BlocBase {
  void dispose();
}

1 Ответ

1 голос
/ 07 апреля 2019

Лучший способ найти исходный блок в новом контексте - это передать ссылку на него новому блоку, который управляет логикой нового контекста.Чтобы сохранить код модульным, каждый блок не должен контролировать более одной страницы логики или одной вещи (например, состояние входа пользователя в систему).Поэтому, когда я создаю новый экран / контекст с помощью showDialog (), у меня также должен быть новый блок, который работает с логикой на этом экране.Если мне нужна ссылка на исходный блок, я могу передать ее конструктору нового блока через конструктор виджета диалога, поэтому новый блок / контекст может получить доступ к любой информации в исходном блоке:

    child: FloatingActionButton(
      onPressed: () => showDialog(
        context: context,
        builder: (newContext) => NewEventDialog(
          accountBloc: BlocProvider.of<AccountBloc>(context),
        ),
      ).then((event) => eventsBloc.addEvent(event)),

...

class NewEventDialog extends StatelessWidget {
  final AccountBloc accountBloc;
  NewEventBloc _newEventBloc;

  NewEventDialog({this.accountBloc}) : assert(accountBloc != null);

  @override
  Widget build(BuildContext context) {
    _newEventBloc = NewEventBloc(accountBloc: accountBloc);

    return BlocProvider(
      bloc: _newEventBloc,
...
...