【问题标题】:Can I skip BlocBuilder render in some case?在某些情况下我可以跳过 BlocBuilder 渲染吗?
【发布时间】:2019-05-24 03:22:46
【问题描述】:

有一块屏幕有MyBloc myBloc

在screen的build方法中是这样的:

Widget build(BuildContext context) {
    return MyCustomLoadingStack( //My custom widget to have the main content below the loading widget
        _buildContent(context), //My main content
        _buildLoading(context)); //My loading on top
}

还有我的2个方法:

Widget _buildContent(BuildContext context) {
 return Column(children: <Widget>[
      OtherWidgetOne(),
      OtherWidgetTwo(),
      BlocBuilder<MyEvent, MyState>(
          bloc: myBloc,
          builder: (BuildContext context, MyStatestate) {
            switch (state.type) {
              case MyStateList.doneWorking:
                return MyDataWidget(); // this content cares about displaying the data only
              default:
                return Container(); //otherwise display nothing
            }
          },
        )
]);

}

Widget _buildLoading(BuildContext context) {
 return BlocBuilder<MyEvent, MyState>(
          bloc: myBloc,
          builder: (BuildContext context, MyState state) {
            switch (state.type) {
              case MyStateList.loading:
                return LoadingView(); //This _buildLoading cares the loading only
              default:
                return Container(); //If it's not loading the show nothing for the loading layer
            }
          },
        )
}

我的问题是内容当前显示数据的时间。当我yield MyState(type: MyStateList.loading) 在做其他事情时显示加载(比如为当前显示的数据加载更多)。两个BlocBuilder 都被调用,然后_buildContent(context) 什么也不显示,因为它不满足MyStateList.doneWorking 条件。当然,_buildLoading(context) 会在下面显示一个空内容的加载。

无论如何我可以跳过 _buildContent(context) 中的 BlocBuilder 以继续显示当前数据并仍然在顶部加载吗?

我想有一个小部件来包含数据或空Container() 以在_buildContent(context) 的默认情况下使用,但这对我来说没有意义,因为它们可能会重新呈现相同的小部件。

感谢您的宝贵时间。

【问题讨论】:

    标签: flutter loading bloc


    【解决方案1】:

    好问题!您使用 BlocBuilder 而不是 StreamBuilder 有什么原因吗?

    要在加载数据时不显示任何内容并在加载后自动填充数据,我通常会执行以下操作:

       Widget _buildLoading(BuildContext context) {
         return StreamBuilder<Model>(
                  stream: bloc.modelStream,
                  builder: (context, snapshot) {
    
        if (snapshot.hasError) return _buildErrorWidget(snapshot.error, context);
    
        if (snapshot.hasData) {
                  return DesiredWidget()
        } else {
        return LoadingView()
        }
    }
    

    我没有看到您的 BloC 文件,但您可能需要添加几行,如下所示:

    final _modelFetcher = BehaviorSubject<Model>();
    Stream<Model> get modelStream => _modelFetcher.stream;
    
    Function(Model) get changeModelFetcher => _modelFetcher.sink.add;
    
    
    @override
      void dispose() async {
        await _modelFetcher.drain();
        _modelFetcher.close();
    }
    

    让我知道这是否有帮助。

    【讨论】:

    • 一开始我使用StreamBuilder,每次需要加载或不加载时我都会调用_isLoadingStreamController.sink.add(true)(或false)。但是我在某处读到,如果我这样使用,它就像方法调用,它不再是基于事件的块,这就是我使用 BlocBuilder 来处理状态的原因。我在这两者之间有点混淆。也许我可以将BlocBuilder 用于主要内容,将StreamBuilder 用于加载小部件。但在这种情况下,不再需要BlocBuilder,因为它只处理数据为空或不为空的一种情况。然后我可以使用Streambuilder,甚至是错误弹出,...
    【解决方案2】:

    现在讨论了一个 pullrequest 来解决这个问题: https://github.com/felangel/bloc/issues/315?fbclid=IwAR2x_Q1x5MIUUPE7zFRpjNkhjx5CzR0qiRx-P3IKZR_VRGEp3eqQisTthDo

    目前,您可以将类用于更复杂的状态。这可能是这样的:

    class MyState extends Equatable {
      final bool isLoading;
      final List<MyData> data;
      bool get hasData => data.isNotEmpty;
    
      MyState(this.isLoading,this.data) : super([isLoading,data]);
    }
    

    我使用 Equatable (https://pub.dev/packages/equatable) 来更轻松地实现 isEqual。

    Widget _buildContent(BuildContext context) {
      return Column(children: <Widget>[
        OtherWidgetOne(),
        OtherWidgetTwo(),
        BlocBuilder<MyEvent, MyState>(
          bloc: myBloc,
          builder: (BuildContext context, MyStatestate) {
            if (state.hasData) {
              return MyDataWidget(); // this content cares about displaying the data only
            } else {
              return Container(); //otherwise display nothing
            }
          },
        )
      ]);
    }
    
    Widget _buildLoading(BuildContext context) {
      return BlocBuilder<MyEvent, MyState>(
        bloc: myBloc,
        builder: (BuildContext context, MyState state) {
          if (state.isLoading) {
              return LoadingView(); //This _buildLoading cares the loading only
          } else {
            return Container(); //If it's not loading the show nothing for the loading layer
          }
        },
      );
    }
    

    这种方法的缺点是,即使数据没有改变,数据小部件也会重绘。这将通过提到的 pullrequest 解决。

    【讨论】:

    • 从您提供的链接中,我看到了这个库pub.dev/packages/flutter_bloc_extensions,在我们等待修复时可能会派上用场。谢谢你的信息。
    • 不错的发现,不知道那个。看起来很有用
    猜你喜欢
    • 2014-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-11
    • 2021-11-22
    • 1970-01-01
    • 2017-05-15
    • 2022-11-03
    相关资源
    最近更新 更多