Bloc: Rebuild bloc with the same state

Created on 19 Aug 2019  路  7Comments  路  Source: felangel/bloc

Hello MR Felix,

I just want to ask, is there a way to rebuild bloc but the next state that we send is the same as the current state but with different data ?

Thank you.

question

Most helpful comment

Ok Thank you @felangel

All 7 comments

Hi @semutnest 馃憢
Thanks for opening an issue!

Regarding your question, yes 馃憤 you just need to make sure you鈥檙e never mutating currentState. Instead, create a new instance and everything should work as you鈥檇 expect.

Are you having trouble getting the expected results? If so, it would be great if you could share a link to a sample app which illustrates the problem you鈥檙e having.

Hope that helps 馃憤

Ok sir, Thank you I will give it a try.

Sorry, Sir

I have not understood what you meant 'create a new instance'
I have a simple example.


//BLOC
class MyBloc extends Bloc {
  @override
  MyState get initialState => InitialState();

  @override
  void onTransition(Transition transition) {
    print(transition);
  }

  @override
  Stream mapEventToState(
    MyEvent event,
  ) async* {
    if (event is TestEvent) {
      if (currentState is TestState) {
        if ((currentState as TestState).status)
          yield TestState(status: !(currentState as TestState).status);
        else
          yield TestState(status: (currentState as TestState).status);
      }  
      else  yield TestState(status: true);   
    }
  }
}

//EVENT
abstract class MyEvent extends Equatable {
  MyEvent([List props = const []]) : super(props);
}

class TestEvent extends MyEvent {  
  @override
  String toString() => 'TestEvent';
}

//STATE
abstract class MyState extends Equatable {
  MyState([List props = const []]) : super(props);
}

class InitialState extends MyState {
  @override
  String toString() => 'InitialState';
}

class TestState extends MyState {
  final bool status;
  TestState({@required this.status}) : super([status]);
  @override
  String toString() => 'TestState';
}

class OtherState extends MyState {
  @override
  String toString() => 'OtherState';
}

//MAIN
void main() {
  runApp(
    BlocProvider(
      builder: (context) => MyBloc(),
      child: App(),
    ),
  );
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final MyBloc myBloc = BlocProvider.of(context);
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(title: Text('Flutter')),
          body: BlocBuilder(builder: (context, state) {
            print("REBUILD BLOC");
            if (state is TestState) {
              if (state.status)
                return Center(child: Text("TRUE"));
              else
                return Center(child: Text("NOT TRUE"));
            } 
            return Center(child: Text("NO DATA"));           
          }),
          floatingActionButton: FloatingActionButton(
              child: Icon(Icons.account_circle),
              onPressed: () {
                myBloc.dispatch(TestEvent());
              },
            ),
          ),
    );
  }
}

From this example, the first and second press button rebuild the bloc but not the next press.
can you provide hints for this;

Thanks a lot.

Hi @semutnest the problem in your example is when status == false you always yield TestState(status: (currentState as TestState).status);

By default, if you yield a state where state == currentState, then no transition will occur (docs).

If you update your example to:

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

class MyBloc extends Bloc<MyEvent, MyState> {
  @override
  MyState get initialState => InitialState();

  @override
  void onTransition(Transition transition) {
    print(transition);
  }

  @override
  Stream<MyState> mapEventToState(MyEvent event) async* {
    final state = currentState;
    if (event is TestEvent) {
      if (state is TestState) {
        yield TestState(status: !state.status);
      } else
        yield TestState(status: true);
    }
  }
}

//EVENT
abstract class MyEvent extends Equatable {
  MyEvent([List props = const []]) : super(props);
}

class TestEvent extends MyEvent {
  @override
  String toString() => 'TestEvent';
}

//STATE
abstract class MyState extends Equatable {
  MyState([List props = const []]) : super(props);
}

class InitialState extends MyState {
  @override
  String toString() => 'InitialState';
}

class TestState extends MyState {
  final bool status;
  TestState({@required this.status}) : super([status]);
  @override
  String toString() => 'TestState { status: $status }';
}

class OtherState extends MyState {
  @override
  String toString() => 'OtherState';
}

//MAIN
void main() {
  runApp(
    BlocProvider(
      builder: (context) => MyBloc(),
      child: App(),
    ),
  );
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final MyBloc myBloc = BlocProvider.of<MyBloc>(context);
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Flutter')),
        body: BlocBuilder<MyBloc, MyState>(
          builder: (context, state) {
            print("REBUILD BLOC");
            if (state is TestState) {
              if (state.status)
                return Center(child: Text("TRUE"));
              else
                return Center(child: Text("NOT TRUE"));
            }
            return Center(child: Text("NO DATA"));
          },
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.account_circle),
          onPressed: () {
            myBloc.dispatch(TestEvent());
          },
        ),
      ),
    );
  }
}

Then everything will work as expected.

Hope that helps 馃憤

Ok Thank you @felangel

@felangel Hi sir! I'm having the same problem with version 6.0.1. Can you give me an example on how to rebuild with the same State when i trigger events?

@manhDat0301 hey you can just avoid extending Equatable and yield a new instance of your state -- that hasn't changed for v6.0.1.

Was this page helpful?
0 / 5 - 0 ratings