'how to reuse previous state fields in flutter bloc pattern?
have the following. using sliding_up_panel that has body with messages and with a different view in panel content that pops up on click action from bottom bar.
@override
Stream<AppState> mapEventToState(
AppEvent event,
) async* {
if (event is LoadChat) {
List<Msg> msgs = await Api.getMessages();
yield LoadedChat(messages: msgs);
} else if (event is OrderPanelOpen) {
yield OpenedPanelState();
} else if (event is OrderPanelClose) {
yield ClosedPanelState();
}
}
Goal is to hide the appBar when panel is opened. appBar is present in AppLayout which is parent holding the SlidingUpPanel widget itself in a Scaffold.
class _AppLayoutState extends State<AppLayout> {
@override
Widget build(BuildContext context) {
var bloc = BlocProvider.of<AppBloc>(context);
return Container(
child: Scaffold(
appBar: widget.showAppBar
? AppBar(...)
: null,
bottomNavigationBar: BottomAppBar(...),
body: SlidingUpPanel(...),
),
);
}
}
following is the action that adds panel events to bloc
IconButton(
icon: Icon(Icons.description),
onPressed: () {
if (widget.pannelCtrl.isPanelClosed()) {
widget.pannelCtrl.open();
bloc.add(OrderPanelOpen());
} else {
widget.pannelCtrl.close();
bloc.add(OrderPanelClose());
}
})
problem here is SlidingUpPanel has a body that needs to show messages regardless of panel open or close. If panel open and close events are mapped to states with bloc, these open and close events has to be separate states but messages from current state has to be passed to new state by either as constructor params to new state or other ways. is that right approach to achieve this or is there anything else cleaner that I'm missing here.
class ClosedPanelState implements LoadedChat {
final messagesArg;
ClosedPanelState({this.messagesArg});
@override
Widget get currentView => Chat(messages: this.messagesArg);
@override
List<Object> get props => [];
@override
bool get showAppBar => true;
@override
String get title => 'Order Food';
@override
List<Msg> get messages => messages;
}
Solution 1:[1]
According to your question's title there's a thing you can do.
For your bloc class you can create a stack-like variable (you can use your own implementation of a LIFO stack or use a List, as you wish). Your bloc class must be Singleton in order to save the Events.
static final List<AppEvent> _events = new List<AppEvent>();
And on your _mapEventToState implementation add the events called to the variable:
@override
Stream<AppState> mapEventToState(
AppEvent event,
) async* {
_events.add(event); // New Line
if (event is LoadChat) {
List<Msg> msgs = await Api.getMessages();
yield LoadedChat(messages: msgs);
} else if (event is OrderPanelOpen) {
yield OpenedPanelState();
} else if (event is OrderPanelClose) {
yield ClosedPanelState();
}
}
Later you write a method for calling the last Event on the Stack/List.
dispatchPreviousState() {
this.add(_events.removeLast());
}
This worked for me to get the latest Event called and dispatching it again.
Solution 2:[2]
You can use reversible_bloc to add this behaviour to your bloc / cubit.
Ex.:
class MyReversibleCubit extends Cubit<int> with ReversibleBlocMixin {
MyReversibleCubit(int initialState) : super(initialState);
void changeValue(int newValue) => emit(newValue);
}
Then, when you need to rollback, use revert()
final myReversibleCubit = context.read<MyReversibleCubit>();
myReversibleCubit.changeValue(2);
myReversibleCubit.changeValue(4);
// Current state is 4
myReversibleCubit.revert();
// Current state back to 2
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Andrés Escobar Pérez |
Solution 2 | Guilherme Gabanelli |