Bloc: Does the current state needs all properties that should be rendered by the current view?

Created on 20 Aug 2020  ·  2Comments  ·  Source: felangel/bloc

Hi,
I have a question of understanding regarding the usage and interaction of the states and views/widgets:

Let’s say you have a button and two Text widgets (A & B).
One Text widget A is initialized with a value during the initial state, such as

abstract class MyState{}

class MyInitalState extends MyState{
    int valueA;
    MyInitalState (this.valueA)
}

The second Text widget B updates its value after the button was pressed with a different state that looks like this:

class MySecondState extends MyState{
    int valueB;
    MySecondState (this.valueB)
}

After launching the screen, Text widget A automatically receives and render its value due to MyInitalState. Text widget B shows nothing.

When you press the button, an event triggers a state change. As a result, MySecondState was passed to the stream.
B reacts to this state change and consumes the value.
Text widget A does not build when this state is triggered because of the following condition: buildWhen: (previousState, state) => state is! MySecondState;. Therefore, it only is able to consume the value of MyInitalState.
Finally, both Text widgets have their respective values.

Although, when you change the orientation of the device. The value of setState method is called and Flutter rebuilds the whole screen.
All BlocBuilder widgets try to rebuild themselves by reacting to the last triggered state (MySecondState, the current state actually) and buildWhen is never called (most likely because of the complete rebuild) and because the state is not MyInitalState it, for example renders nothing. Consequently, Text widget A “loses” its value, but B again receives its value from MySecondState.

To ensure that the value of A is also preserved, you somehow have to pass the value of A to MySecondState (e.g. by extending from MyInitalState)

I did a lot of research and also found a lot of comments of @felangel like:

The builder method can be invoked many times by Flutter and it's totally normal.

The build method is designed in such a way that it should be pure/without side effects. This is because many external factors can trigger a new widget build, such as:

Route pop/push, for in/out animations
Screen resize, usually due to keyboard appearance or orientation change
Parent widget recreated its child
An InheritedWidget the widget depends on (Class.of(context) pattern) change

which supports my understanding.

Do I always have to make sure that the current state always has all necessary properties for the current view? Is this the concept or do I miss something?

Thank you in advance!

Best regards!
Pat

question

All 2 comments

Hi @patgdev 👋

You're right. your first text widget looses it's value as a result of the full rebuild caused by the orientation change.
I feel you should try avoiding buildWhen conditions based on state type, but rather use state values, e.g.:
buildWhen: (previous, current) => previous.valueA != current.valueA.

In your case you want to keep both values for your texts so it's recommended to use a single state class which holds both valueA and valueB. As a performance improvement you can make use of buildWhen as suggested above.

Hope that clear things for you 👍

Hi @RollyPeres :1st_place_medal: ,

thank you for your quick response and confirming my "findings" :-)
Now, I have the feeling that I understand how I have to use this great library.

Your hint regarding the usage of 'buildWhen` also makes sense to me.

Again a big thank you! :+1:

Was this page helpful?
0 / 5 - 0 ratings