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.
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.
Most helpful comment
Ok Thank you @felangel