多个BLoC:如何嵌套BlockBuilder

时间:2019-02-27 12:37:56

标签: flutter

我正在设计一个BlocBuilder嵌套在另一个BlocBuilder中的应用。

将事件调度到嵌套ServiceBloc时,页面未按预期刷新:嵌套BlocBuiler.builder未触发。

这种方法有什么问题?

在MVCE下面再现了问题。

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:bloc/bloc.dart';

void main() async {
  runApp(App());
}

class App extends StatefulWidget {
  @override
  AppState createState() {
    return new AppState();
  }
}

// AppBloc states
class ServicePage {}

class SearchState extends ServicePage {}

class AllServices extends ServicePage {}
// end of AppBloc states

// AppBloc events
class AppEvent {}

class EnableSearch extends AppEvent {}

class DisableSearch extends AppEvent {}
// end of AppBloc events

class AppBloc extends Bloc<AppEvent, ServicePage> {
  @override
  ServicePage get initialState => AllServices();

  @override
  Stream<ServicePage> mapEventToState(
      ServicePage currentState, AppEvent event) async* {
    if (event is EnableSearch) {
      yield SearchState();
    } else {
      yield AllServices();
    }
  }
}

// ServiceBloc events
class ServiceEvent {}

class ServicesLoaded extends ServiceEvent {}

class ServiceFilter extends ServiceEvent {
  String pattern;

  ServiceFilter(this.pattern);
}
// end of ServiceBloc events

class ServiceBloc extends Bloc<ServiceEvent, List<String>> {
  List<String> services = ["aa", "bb", "cc"];

  @override
  List<String> get initialState => services;

  @override
  Stream<List<String>> mapEventToState(
      List<String> currentState, ServiceEvent event) async* {
    if (event is ServiceFilter) {
      yield services.where((service) => service.contains(event.pattern));
    } else {
      yield services;
    }
  }
}

class AppState extends State<App> {
  final TextEditingController _filter = TextEditingController();

  final AppBloc appBloc = AppBloc();
  final ServiceBloc serviceBloc = ServiceBloc();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.red,
      ),
      home: BlocBuilder(
          bloc: appBloc,
          builder: (BuildContext context, ServicePage sts) {
            var searchBar;
            if (sts is AllServices) {
              searchBar = AppBar(title: const Text('MVCE multi bloc'), actions: <Widget>[
                IconButton(
                  icon: Icon(Icons.search),
                  onPressed: () {
                    appBloc.dispatch(EnableSearch());
                  },
                ),
              ]);
            } else {
              searchBar = AppBar(
                  title: TextField(
                    onSubmitted: (val) {
                      print("filter string: $val");
                      serviceBloc.dispatch(ServiceFilter(_filter.text));
                    },
                    controller: _filter,
                    decoration: InputDecoration(
                        prefixIcon: Icon(Icons.search), hintText: 'Search...'),
                  ),
                  actions: <Widget>[
                    IconButton(
                        icon: Icon(Icons.close),
                        onPressed: () {
                          serviceBloc.dispatch(ServiceFilter(_filter.text));
                          appBloc.dispatch(DisableSearch());
                        }),
                  ]);
            }
            return Scaffold(
                appBar: searchBar,
                body: ServicesWidget(serviceBloc));
          }),
    );
  }
}

class ServicesWidget extends StatelessWidget {
  final ServiceBloc bloc;

  ServicesWidget(this.bloc);

  @override
  Widget build(BuildContext context) {
    return BlocBuilder(
        bloc: bloc,
        builder: (BuildContext context, List<String> services) {
          print("Rebuilding list view");
          return ListView.builder(
              itemCount: services.length,
              itemBuilder: (BuildContext context, int index) {
                return SizedBox(
                  height: 100,
                  child: Card(
                      child: Column(
                    children: <Widget>[
                      Text(services[index]),
                    ],
                  )),
                );
              });
        });
  }
}

1 个答案:

答案 0 :(得分:0)

该问题与BlocBuilder的嵌套无关,而与mapEventToState的实现有关:

Stream<List<String>> mapEventToState(
    List<String> currentState, ServiceEvent event) async* {
  if (event is ServiceFilter) {
    yield services.where((service) => service.contains(event.pattern));
  } else {
    yield services;
  }
}

service.where()返回一个WhereIterable,而不是字符串列表。

由于某种原因,我不知道,该异常被静默捕获,并且不会调用BlocBuilder的构建器小部件。

以下内容具体化了一个列表并使其成为多块示例:

Stream<List<String>> mapEventToState(
    List<String> currentState, ServiceEvent event) async* {
  if (event is ServiceFilter) {
    yield services.where((service) => service.contains(event.pattern)).toList();
  } else {
    yield services;
  }
}