BLoC 和多个流 - 有更好的解决方案吗?

BLoCs and multiple streams - Is there a better solution?

目前我正在 Flutter 中使用 BLoC,我有一个关于 Bloc 中的多个流的问题。

例如,当一个屏幕有多个应该依赖于 Bloc 的小部件时。我可以将整个屏幕包裹在 StreamBuilder 中,但是每次都会重建所有小部件。

示例集团:

class TestBloc {
  final StreamController _dataController = StreamController<String>();
  final StreamController _appBarTitleController = StreamController<String>();

  TestBloc();

  Stream<String> get appBarTitle => _appBarTitleController.stream;

  Stream<DataState> get data => _dataController.stream;

  void fetchData(String path) async {
    _dataController.sink.add(PokemonDataLoading());

    Data data = await _getData();

    _dataController.sink.add(Loaded(data));
    _appBarTitleController.sink.add(data.name);
  }

  Future<Data> _getData(String path) async {
    return await _dataRepository.fetchData(path);
  }

  void dispose() {
    _dataController.close();
    _appBarTitleController.close();
  }
}

在示例构建方法中,您可以看到两种不同的 StreamBuilder,一种用于应用栏标题,一种用于内容。当然,我可以在这个示例中将它们包装到一个 StreamBuilder 中,但有时这并不容易实现。它们可能取决于其他数据或用户交互。

@override
Widget build(BuildContext context) {
  _testBloc.fetchData();

  return ScaffoldWithSafeArea(
    title: StreamBuilder(
      stream: _testBloc.appBarTitle,
      builder: (context, AsyncSnapshot<String> snapshot) {
        if (snapshot.hasData) {
          return Text(snapshot.data);
        }
        return Text("Test");
      },
    ),
    child: StreamBuilder<DataState>(
      stream: _testBloc.data,
      builder: (context, AsyncSnapshot<DataState> snapshot) {
        DataState state = snapshot.data;

        if (state is DataInitial) {
          return _buildLoading();
        } else if (state is DataLoaded) {
          return _buildContent(state.data);
        }
        return _buildLoading();
      },
    ),
  );
}

对于一屏多流,是否有更好的解决方案?我在这里使用了很多样板代码,希望避免这种情况。

为了在一个屏幕上管理多个流,最好的解决方案是让多个小部件监听相应的流。

通过这种方式,您可以通过优化小部件的构建总数来提高应用程序的性能。

通过这样做,您可以创建小部件来侦听 BLoC 的输出(流)并在应用程序的不同部分重用它们,但是为了使小部件可重用,您需要将 BLoC 注入到小部件中.

如果您看到 BLoC UI design guidelines

Each "complex enough" component has a corresponding BLoC

这样你的屏幕现在将由不同的组件组成,这个组件是一个小部件,可以监听你的 BLoC 的输出(流)。

所以你做对了。

如果您想减少小部件中的重复代码,您可以:

  • 创建您自己的监听流的小部件并直接 returns BLoC 的输出(在您的情况下您调用状态),这样您就不需要使用 snapshot.data 喜欢 StreamBuilder。此小部件的示例是 BlocBuilder of flutter bloc 库。

  • 使用 flutter bloc library that has widgets that reduce the boilerplate code when use BLoC pattern, but if you use this library, you now need to create your BLoCs using bloc 库,但是如果你这样做,现在你减少了在你的 BLoC 中创建 StreamControllers 的样板代码,以及其他有趣的功能,所以你应该看看 bloc 和 flutter bloc 库的强大功能。