Bloc: [bloc builder] must return a widget, can't ignore "else" statement

Created on 29 Oct 2019  路  7Comments  路  Source: felangel/bloc

Hey, I'm doing some stuff with with flutter_bloc ..I did everything correct.. but I found an issue that might be a confuse one!!
So, let's get to the point.. on BlocBuilder we must return a widget but is there any way to stay to the previous state? since I can't write "else" or return any other widget except the one inside my condition like (if state is LoadingState) then (do stuff) otherwise don't build anything and stay where you were.. that's all...

any solutions? @felangel

here's a screenshot of my code

1

question

Most helpful comment

@felangel that's definitely sounds perfect, I can use StatefulWidget and setState in some little cases... But since I do not prefer to do that.. I wrote a simple trick that won't effects everything and works with the same performance as I want.
Thank you so much for your time 鉂わ笍 and helped me a lot.

All 7 comments

Hi @abdulmuaz97 馃憢
Thanks for opening an issue!

BlocBuilder must return a widget by definition (see definition). It's the same reason why you can't have the following widget:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
     if (condition) {
       return WidgetA();
     }
     // otherwise do nothing
   }
}

A widget's build method is a pure function meaning it does not "remember" anything (it's stateless after all) and as a result you can't expect it to "stay where it was".

Hope that helps clarify things but your question is not bloc-specific this is how Flutter was designed 馃憤

yes it's absolutely right what you said ... So we don't have any solution except I did this to prevent that happening, but still rebuild the widget and this is how Flutter works as you mentioned there..

// inside StatefulWidget [Global Variable]
int currentPageIndex = 0;
.
.
// iside BlocBuilder
builder: (context, state) {
    if (state is GetPageIndex) {
        currentPageIndex = state.index;
        _buildNavBar(state.index);
    }
    return _buildNavBar(currentPageIndex);
},

I guess this is might be a better solution for this issue!

You should not have a StatefulWidget because your state should all be coming from the bloc. In what case would your state not be GetPageIndex? Can you share what all of your bloc states are?

I'm using a BottomNavigationBar and trying to handle onTap where you can move or slide one widget to another... by Bloc.
and the reason I'm using StatefulWidget because there are some TextFields and can't but them inside StatelessWidget ..tried to use only StatelessWidget but this is another issue!

here's my state bloc classes
2

I think the problem is your bloc has too many responsibilities. You should probably refactor to have a single bloc managing the state of the tab like so:

class PageEvent extends Equatable {
  final int index;
  const PageEvent(this.index);

  @override
  List<Object> get props => [index];
}

class PageBloc extends Bloc<PageEvent, int> {
  @override
  int get initialState => 0;

  @override
  Stream<int> mapEventToState(TabEvent event) async* {
    yield event.index;
  }
}

Then you can refactor your UI like:

BlocBuilder<PageBloc, int>(
  builder: (context, index) => _buildNavBar(index),
)

Also keep in mind that you don't need a bloc for everything. In this case, I would argue that there is no business logic involved so you can manage the current index via a StatefulWidget and setState.

Hope that helps and if you haven't already I would highly recommend going through the core concepts.

@felangel that's definitely sounds perfect, I can use StatefulWidget and setState in some little cases... But since I do not prefer to do that.. I wrote a simple trick that won't effects everything and works with the same performance as I want.
Thank you so much for your time 鉂わ笍 and helped me a lot.

Was this page helpful?
0 / 5 - 0 ratings