Flutter BloC not refresh my view (counter app)

I'm trying BloC library with Counter test app but I have a little problem on my view when I use object to increment/decrement my counter. MyObject.MyProperty increment or decrement but my view not refreshed. Why?

Sample app with simple int variable.

My code with object:

import 'dart:async';    
import 'package:flutter/material.dart';    
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';    

void main() { 
  runApp(App());
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: BlocProvider(
        builder: (context) => CounterBloc(),
        child: CounterPage(),
      ),
    );
  }
}

class TestTest{
  int myProperty; 

  TestTest(){
    myProperty = 0;
  }
}


class CounterPage extends StatefulWidget {
  @override
  _CounterPageState createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  @override
  Widget build(BuildContext context) {
    final counterBloc = BlocProvider.of<CounterBloc>(context);

    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: BlocBuilder<CounterBloc, TestTest>(
        builder: (context, myClassTestTest) { 
          return Center(
            child: Text(
              '${myClassTestTest.myProperty}',
              style: TextStyle(fontSize: 24.0),
            ),
          );
        },
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Padding(
            padding: EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: Icon(Icons.add),
              onPressed: () {
                counterBloc.dispatch(CounterEvent.increment);
              },
            ),
          ),
          Padding(
            padding: EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: Icon(Icons.remove),
              onPressed: () {
                counterBloc.dispatch(CounterEvent.decrement);
              },
            ),
          ),
        ],
      ),
    );
  }
}


enum CounterEvent { increment, decrement }

class CounterBloc extends Bloc<CounterEvent, TestTest> {
  @override
  TestTest get initialState => TestTest();

  @override
  Stream<TestTest> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.decrement:        
        currentState.myProperty -= 1;
        yield currentState; 
        break;
      case CounterEvent.increment:
        currentState.myProperty += 1;
        yield currentState; 
        break;
    }
  }
}

As you can see I edited the sample app a little just to add my class TestTest with a int property myProperty. When I clic on my button the value in my object change but my view is not refreshed.

How can I fix that?

I found a solution to recreate my TestTest in mapEventToState but it's weird to recreate an entire object just to update a property...

Thank you

I see you are using some kind of redux implementation and i'm not quite sure how this handles the rebuild when actions are dispatched.

As my knowledge you are dispatching an action that update some property on the widget but you are never calling setState again, so the widget is not being rebuild.

Try to call the increment or decrement actions inside a setState function.

Something like this:

onPressed: () {
 setState(() => counterBloc.dispatch(CounterEvent.decrement));
},

flutter_bloc, Flutter Widgets that make it easy to implement the BLoC (Business Logic *Note : All widgets exported by the flutter_bloc package integrate with AppBar(title: const Text('Counter')), body: BlocBuilder<CounterCubit, The app uses a RefreshIndicator to implement "pull-to-refresh" as View/report issues´┐Ż Examples #. Counter - an example of how to create a CounterBloc to implement the classic Flutter Counter app.; Form Validation - an example of how to use the bloc and flutter_bloc packages to implement form validation.

Just posting another possible solution for future visitors.

If you do yield for the same state twice. Your UI won't update.

For example if you have already triggered ShowDataToUser(data) from your Bloc and now after another operation you are yielding ShowDataToUser(data) again, your UI won't update.

A quick hack around this would be to just create a DummyState() in your Bloc and yield DummyState() everytime before you yield ShowDataToUser(data)

Another solution apart from the quick hack around is to define a way for dart to compare and equate a class, cos currently by default ShowDataToUser is the same class, but its contents are different, but Dart doesn't know how to evaluate the content and compare them.

Enters Equatable

For this, you need to use the package : https://pub.dev/packages/equatable

Now you have to extend your Bloc states with Equtable like:

class DummyState extends Equatable {}

Now, if your Bloc States are extending Equatable then you must override the function:

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

Here name is the property/field name you want to compare when comparing two same classes.

This function tells your Bloc, how to differentiate between two same states (which might have different values in them).

bloc_lite_flutter, Includes Flutter widgets to integrate blocs into the Flutter ecosystem. A simplified library for creating stream-based bloc view models that adhere to the BLoC paradigm. insert multiple InheritedBlocs into the widget tree without bloating the from the bloc_lite docs to build a simple counter app in Flutter. For this example, you do not need this BLoC to be available to the whole application but to some Widgets, part of a tree. A first solution could be to inject the BLoC as the root of the Widgets tree, as follows: This way, all widgets will access the BLoC, via a call to the BlocProvider.of method.

I have had same problem, and after googling couple of hour, I have found the solution in https://github.com/felangel/bloc/issues/203#issuecomment-480619554

As shown in the below code, The main problem is that when you yield the state, the previous state and the current state are equal, so blocBuilder have hadn't triggered.

case CounterEvent.decrement:        
  currentState.myProperty -= 1;
  yield currentState; 

You should copy the state, then change and yield it.

final TestTest newState = TestTest();
newState.myProperty = currentState.myProperty;

...

case CounterEvent.decrement:        
  newState.myProperty -= 1;
  yield newState; 

Flutter: BLoC with Streams. This article will help you to get…, The BLoC wraps the business logic and takes events to access the functionality with streams. Create a new Flutter project and get the IncrementApp running, the Flutter app which is always created controls the stream of counter events and exposes the sink of events. Update UI with StreamBuilder. I/flutter ( 6351): BlocProvider.of() called with a context that does not contain a Bloc of type CounterBloc. I/flutter ( 6351): No ancestor could be found starting from the context that was passed to I/flutter ( 6351): BlocProvider.of(). This can happen if the context you use comes from a widget above the I/flutter ( 6351): BlocProvider.

Flutter for Android developers, Views. What is the equivalent of a View in Flutter? How do I update widgets? Note: To integrate Flutter code into your Android app, see Add Flutter to existing app. you would typically move to a background thread and do the work, as to not block the main thread, and avoid ANRs. 0) + 1; print('Pressed $counter times. Flutter. Counter - an example of how to create a CounterBloc to implement the classic Flutter Counter app. Form Validation - an example of how to use the bloc and flutter_bloc packages to implement form validation. Bloc with Stream - an example of how to hook up a bloc to a Stream and update the UI in response to data from the Stream.

Getting Started with the BLoC Pattern, See how to use the popular BLoC pattern to architect your Flutter app and manage the The Model and View are separated, with the Controller sending signals between them. Note: It's a best practice for production apps to not store your API keys in Finally, update main.dart to return the new screen. I am trying to build a shopping cart using the bloc pattern as this my first app in flutter as well as using bloc. my problem is that I am trying to get the stream of an int each time the user add

flutter_bloc, Built to be used with the bloc state management package. Counter - an example of how to create a CounterBloc to implement the classic Flutter Counter app. firestore todos tutorial with flutter_bloc - How to create a todos app using the bloc and flutter_bloc packages that integrates with cloud firestore. Extensions IntelliJ - extends IntelliJ/Android Studio with support for the Bloc library and provides tools for effectively creating Blocs for both Flutter and AngularDart apps.

Comments
  • can you give your exact solution for this ? I'd like to see how to solve this, thanks.
  • Switching in Stateful and using setState works for me. We can't refresh UI because my object is immutable: github.com/felangel/bloc/issues/103
  • this solution maybe works sometimes, but it's not a good idea. bloc should change the state automatically without setState
  • This was the perfect solution for me. I wonder why we have to yield 2 states for this to work.
  • I am not clear how did you solve this as I have the same problem. Can you elaborate. This is my problem. stackoverflow.com/questions/62132532/… @devDeejay
  • Hope it helps @Axil