Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug?] Listener called when being rebuilt, even though no state changes #368

Closed
matanshukry opened this issue Jun 22, 2019 · 10 comments

Comments

@matanshukry
Copy link

commented Jun 22, 2019

Describe the bug
I have 2 pages with BlocListener in each of them. The Blocs them selves are kept in the
I have a BlocListener on my widget

To Reproduce
Create an app widget with blocs in the state.
Create 2 pages that you can navigate between them
In each page have a BlocListener widget on a state. Make sure the state doesn't change when navigating.

The 'listener' callback will be called every time the BlocListener is rebuilt, even though the state is the same.

Expected behavior
The listener callback in BlocListener should only be called once when the state changes, regardless if the BlocListener was just built or not.

**Logs **

$ flutter analyze
Analyzing my-app...
No issues found! (ran in 5.5s)

Paste the output of running flutter doctor -v here.

[√] Flutter (Channel dev, v1.7.4, on Microsoft Windows [Version 10.0.18362.175], locale en-US)
    • Flutter version 1.7.4 at C:\Flutter
    • Framework revision dfecafa4ab (7 days ago), 2019-06-14 09:46:23 -0700
    • Engine revision 2589785b5c
    • Dart version 2.4.0

[√] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at C:\Android\Sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.3
    • ANDROID_HOME = C:\Android\Sdk
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)
    • All Android licenses accepted.

[√] Visual Studio - develop for Windows (Visual Studio Community 2017 15.9.10)
    • Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2017\Community
    • Visual Studio Community 2017 version 15.9.28307.557

[√] Android Studio (version 3.4)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin version 36.1.1
    • Dart plugin version 183.6270
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)

[√] IntelliJ IDEA Community Edition (version 2019.1)
    • IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2018.1.2
    • Flutter plugin version 36.0.4
    • Dart plugin version 191.7830

[√] Connected device (1 available)
    • Android SDK built for x86 • emulator-5554 • android-x86 • Android 9 (API 28) (emulator)

• No issues found!

@matanshukry matanshukry changed the title [Bug?] Listener called first time when being rebuilt, even though no state change [Bug?] Listener called when being rebuilt, even though no state change Jun 22, 2019

@matanshukry matanshukry changed the title [Bug?] Listener called when being rebuilt, even though no state change [Bug?] Listener called when being rebuilt, even though no state changes Jun 22, 2019

@felangel felangel added this to In progress in bloc Jun 23, 2019

@felangel felangel moved this from In progress to To do in bloc Jun 23, 2019

@felangel felangel self-assigned this Jun 23, 2019

@felangel felangel moved this from To do to In progress in bloc Jun 23, 2019

@felangel

This comment has been minimized.

Copy link
Owner

commented Jun 24, 2019

Fixed by #370 and released in flutter_bloc v0.18.2 🎉

@felangel felangel closed this Jun 24, 2019

@felangel felangel removed the in progress label Jun 24, 2019

@felangel felangel moved this from In progress to Done in bloc Jun 24, 2019

@biklas7

This comment has been minimized.

Copy link

commented Jun 27, 2019

Hello @felangel. First of all, thank you for this awesome package!

Regarding this issue. You say in the readme file that: listener is only called once for each state change (including initialState) unlike builder in BlocBuilder and is a void function. I think that with this change the listener is not triggered for the initialState. Can you confirm this?

@felangel

This comment has been minimized.

Copy link
Owner

commented Jun 27, 2019

Hey @biklas7 👋

Yeah you're totally right! I need to update the documentation to say listener is only called once for each state change (not including initialState) unlike builder in BlocBuilder and is a void function. Thanks for pointing this out 💯 (fixed in bedd754)

@biklas7

This comment has been minimized.

Copy link

commented Jun 27, 2019

Maybe I shouldn't put this here but in a project that I'm working on, I was relying on the listener to be called for the initialState to dispatch an event. Since this is not possible, what do you suggest us to do? Maybe convert to a StatefulWidget and dispatch the event in the initState? I don't think this is the best solution 🤔

@felangel

This comment has been minimized.

Copy link
Owner

commented Jun 27, 2019

@biklas7 you can just dispatch the event right when the bloc is created like so:

BlocProvider(
  builder: (context) => MyBloc()..dispatch(MyBlocEvent()),
  child: Container(),
)
@biklas7

This comment has been minimized.

Copy link

commented Jun 27, 2019

@felangel thank you 👍 Keep up the awesome work on your packages!

@bobwiller

This comment has been minimized.

Copy link

commented Jun 28, 2019

@felangel can you provide some guidance around when to use BlocListener vs BlocBuilder? If "BlocBuilder analogous to StreamBuilder", what is BlocListener analogous to?
Thx

@felangel

This comment has been minimized.

Copy link
Owner

commented Jun 28, 2019

@bobwiller BlocBuilder should only be used to return different widgets based on the bloc state. For things like navigation, showing alerts, showing SnackBars, etc ... you should use BlocListener. This is because BlocBuilder can be called many times by the flutter framework whereas BlocListener is only called once per state change. BlocListener is analogous to manually listening to changes in the bloc state and disposing the subscription.

Check out the SnackBar Recipe for more detail 👍

@bobwiller

This comment has been minimized.

Copy link

commented Jun 28, 2019

@felangel thx - i feel like the warning at the bottom of that recipe ("We should NEVER....") should be in the BlocBuilder documentation and/or have a reference to that recipe in the BlocListener doc page!

One last question: I feel like you moved to a pattern where you do:
bloc: BlocProvider.of<DataBloc>(context)

...when you need a reference to the Bloc. So in that recipe, you make that call twice - once in the Listener and again in the Builder vs. getting the reference in the constructor like this:
DataBloc _dataBloc = BlocProvider.of<DataBloc>(context)

and just reusing the reference when you need it. I assume there is a reason for this?

@felangel

This comment has been minimized.

Copy link
Owner

commented Jun 28, 2019

Good point! I’ll make that change 👍

You could get the instance in the build method and reuse the reference in both places. You can’t use BlocProvider.of(context) in the constructor because you need to have access to the BuildContext.

The lookup is O(1) so it shouldn’t have any performance impact but I will make that change as well. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
4 participants
You can’t perform that action at this time.