felangel / bloc

A predictable state management library that helps implement the BLoC design pattern
https://bloclibrary.dev
MIT License
11.76k stars 3.39k forks source link

Bloc pattern and ModalRoute.of #146

Closed vitor-gyant closed 5 years ago

vitor-gyant commented 5 years ago

Hi,

While using the Bloc pattern one issue that arrises is how to pass data between pages. For example, during a login flow we should send the credentials to the next screen. One option is basically passing the data into the next page constructor. I like this approach because it explicitly exposes the page dependencies in the constructor instead of using ModalRoute.of in the next page which basically denotes an intrinsic knowledge of something that is not clear for the caller. Although, by using named routes we loose this ability.

However, if the credentials are required in more than one page this approach seems a bit overkill to me. Is there any recommendation while using the bloc framework on how to improve this ?

Another option would be to have the credentials exposed in the root Bloc and then access it using BlocProvider.of from the other Blocs that would need this information. Again, this kind of approach hides the dependencies which restricts the testing capabilities and readability of the code.

Thanks in advance,

felangel commented 5 years ago

Hi @vitor-gyant great question!

As you said you can pass data via constructor and that's a totally valid approach if you only need the data in one place (as you mentioned). This approach works but it's not very flexible.

If you need the data across multiple routes, then I would recommend using BlocProvider and providing the bloc above the MaterialApp (so that it's available by BuildContext in all routes). I don't think that approach hides dependencies and it doesn't restrict the testing capabilities because you can always right tests where you provide a MockBloc and test as you normally would. The only difference is instead of injecting via constructor you would be injecting via BuildContext. You can take a look at the Todo Sample App for one way to do this and also how you can test it.

Another option is you can take a look at other dependency injection solutions in Flutter like kiwi. It all comes down to what approach works best for you 👍

Let me know if that helps and thanks again for the great question! 💯

vitor-gyant commented 5 years ago

Hi @felangel,

Ok it makes sense.

Let me just ask one more question that is annoying me. Whenever I perform a Navigator.push in a given widget the build method of the current widget page is also triggered. This seems a bit odd to me but I read that it is the expected behaviour.

The problem is that since I'm using BlocBuilder inside of the build method the code for the current state gets executed twice. The code can be something like presenting an alert dialog.

Maybe I'm using the bloc pattern incorrectly but for me it makes sense to trigger an alert dialog inside of the bloc builder whenever a given state is triggered.

Glad to hear your comments.

Thanks again,

felangel commented 5 years ago

@vitor-gyant are you able to share a small sample app which illustrates the problem? Thanks!

vitor-gyant commented 5 years ago

@felangel I've tried on the weather demo app from bloc examples and it happens too. For example, after pressing the settings button the BlocBuilder at line 70 will fire with the same state it was triggered before.

Thanks,

felangel commented 5 years ago

@vitor-gyant that's likely because the entire widget is being rebuilt and it is outside of the scope of bloc. Flutter can decide to rebuild any widget at any time according to the Flutter team so this is working as they intended. Based on that it is strongly recommended that your widget be written in a way that has no side effects if it is rebuilt many times. Let me know if that helps.

felangel commented 5 years ago

Closing this for now but feel free to comment with additional questions/comments and I'm happy to reopen it 👍