Флаттер BLoC воссоздан - PullRequest
       6

Флаттер BLoC воссоздан

0 голосов
/ 04 февраля 2019

Я открываю для себя Flutter и шаблон блока и на практике создаю приложение о пицце.

Я использую BlocProvider для доступа к блокам.Это из пакета generic_bloc_provider .Это базовая реализация, использующая InheritedWidget в сочетании с StatelessWidget.

. У меня есть страница с двумя редактируемыми текстовыми полями для названия и цены пиццы, которую я хочу создать.Он поддерживается блоком.

Вот код:

AddPizzaPage.dart:

class AddPizzaPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("Building AddPizzaPage");
    return Scaffold(
      appBar: AppBar(
        title: Text("Adding Pizza"),
      ),
      body: BlocProvider(
        bloc: AddPizzaBloc(),
        child: ModifyPizzaWidget(),
      ),
    );
  }
}

ListPage.dart:

class ModifyPizzaWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final addPizzaBloc = BlocProvider.of<AddPizzaBloc>(context);
    return Container(
      margin: EdgeInsets.all(16.0),
      child: Column(
        children: <Widget>[
          TextField(
            decoration: InputDecoration(hintText: "Nom de la pizza"),
            onChanged: (name) {
              addPizzaBloc.pizzaNameSink.add(name);
            },
          ),
          TextField(
            decoration: InputDecoration(hintText: "Prix de la pizza"),
            keyboardType: TextInputType.number,
            onChanged: (price) {
              addPizzaBloc.pizzaPriceSink.add(price);
            },
          ),
          IconButton(
            icon: Icon(Icons.check),
            iconSize: 40,
            onPressed: () {
              addPizzaBloc.evenSink.add(AddPizzaEvent.VALIDATE);
              Navigator.of(context).pop();
            },
          )
        ],
      ),
    );
  }
}

AddPizzaBloc.dart:

enum AddPizzaEvent {
  VALIDATE
}

class AddPizzaBloc extends Bloc {
  final _pizza = Pizza.empty();
  final _pizzaSubject = BehaviorSubject<Pizza>();
  final _repository = PizzaRepository();

  Sink<String> get pizzaNameSink => _pizzaNameController.sink;
  final _pizzaNameController = StreamController<String>();

  Sink<String> get pizzaPriceSink => _pizzaPriceController.sink;
  final _pizzaPriceController = StreamController<String>();

  Sink<AddPizzaEvent> get evenSink => _eventSink.sink;
  final _eventSink = StreamController<AddPizzaEvent>();

  AddPizzaBloc() {
    print("Created");
    _pizzaNameController.stream.listen(_addPizzaName);
    _pizzaPriceController.stream.listen(_addPizzaPrice);
    _eventSink.stream.listen(_onEventReceived);
  }

  dispose() {
    print("Disposed");
    _pizzaSubject.close();
    _pizzaNameController.close();
    _pizzaPriceController.close();
    _eventSink.close();
  }

  void _addPizzaName(String pizzaName) {
    _pizza.name = pizzaName;
    print(_pizza);
  }

  void _addPizzaPrice(String price) {
    var pizzaPrice = double.tryParse(price) ?? 0.0;
    _pizza.price = pizzaPrice;
    print(_pizza);
  }

  void _onEventReceived(AddPizzaEvent event) {
    print("Received $event");
    if (event == AddPizzaEvent.VALIDATE) {
      print(_pizza);
      _repository.addPizza(_pizza);
    }
  }
}

Моя проблема заключается в том, что я храню пиццу, которая создается внутри блока, но виджет перестраивается, ипоэтому блок перестраивается, и я теряю состояние.

Полный код доступен на gitlab

Я не знаю, как использовать блок для питания addPizzaформа.

1 Ответ

0 голосов
/ 05 февраля 2019

Это происходит потому, что вы создаете экземпляр вашего BLoC в методе сборки:

BlocProvider(
  bloc: Bloc(),
  child: ...
)

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

Решением будет создание StatefulWidget и создание этого экземпляра BLoC в initState с последующим переопределением dispose для очистки.

Но так как вы используетепакет уже, вы можете использовать провайдера взамен.Это популярная альтернатива, которая делает все перечисленное выше.

Таким образом, ваше использование BlocProvider становится:

StatefulProvider(
   valueBuilder: (_) =>  AddPizzaBloc(),
   dispose: (_, bloc) => bloc.dispose(),
   child: // ...
),

, затем получается так:

Provider.of<AddPizzaBloc>(context);
...