Hello!
I'm developing an app and I have the following BLoCs (for now): Workouts, Exercices, Programs and Calendar.
I have started coding them and I've seen the same pattern when creating the State of each BLoC since I'm working with Streams and they will have nearly the same structure.
Here are my 4 BLoC states:
/// [Workout] state
abstract class WorkoutsState extends Equatable {
const WorkoutsState();
@override
List<Object> get props => [];
}
class WorkoutsInitial extends WorkoutsState {}
class WorkoutsLoading extends WorkoutsState {}
class WorkoutsLoaded extends WorkoutsState {
final List<WorkoutWithExercices> exercices;
const WorkoutsLoaded([
this.exercices = const [],
]);
@override
List<Object> get props => [exercices];
@override
String toString() => 'WorkoutsLoaded(exercices: $exercices)';
}
class WorkoutsNotLoaded extends WorkoutsState {}
/// [Exercise] state
abstract class ExercisesState extends Equatable {
const ExercisesState();
@override
List<Object> get props => [];
}
class ExercicesInitial extends ExercisesState {}
class ExercicesLoading extends ExercisesState {}
class ExercicesLoaded extends ExercisesState {
final List<ExerciseWithTags> exercices;
const ExercicesLoaded([
this.exercices = const [],
]);
@override
List<Object> get props => [exercices];
@override
String toString() => 'ExercicesLoaded(exercices: $exercices)';
}
class ExercicesNotLoaded extends ExercisesState {}
/// [Calendar] state
abstract class CalendarState extends Equatable {
const CalendarState();
@override
List<Object> get props => [];
}
class CalendarInitial extends CalendarState {}
class CalendarLoading extends CalendarState {}
class CalendarLoaded extends CalendarState {
final List<DateWithExercices> exercices;
const CalendarLoaded([
this.exercices = const [],
]);
@override
List<Object> get props => [exercices];
@override
String toString() => 'CalendarLoaded(exercices: $exercices)';
}
class CalendarNotLoaded extends CalendarState {}
/// [Program] state
abstract class ProgramsState extends Equatable {
const ProgramsState();
@override
List<Object> get props => [];
}
class ProgramsInitial extends ProgramsState {}
class ProgramsLoading extends ProgramsState {}
class ProgramsLoaded extends ProgramsState {
final List<ProgramWithWorkouts> exercices;
const ProgramsLoaded([
this.exercices = const [],
]);
@override
List<Object> get props => [exercices];
@override
String toString() => 'ProgramsLoaded(exercices: $exercices)';
}
class ProgramsNotLoaded extends ProgramsState {}
As you can see, they are nearly identical. What I've thought is to create a group of generic state classes like so:
abstract class BaseState<T> extends Equatable {
const BaseState();
@override
List<Object> get props => [];
}
class StateInitial<T> extends BaseState<T> {}
class StateLoading<T> extends BaseState<T> {}
class StateLoaded<T> extends BaseState<T> {
final List<T> items;
const StateLoaded([
this.items = const [],
]);
@override
List<Object> get props => [items];
@override
String toString() => 'StateLoaded(exercices: $items)';
}
class StateNotLoaded<T> extends BaseState<T> {}
So, they will all use this generic state class. What do you think? Do you think it is a good approach? Or you would not recommend using it?
Cheers!
Hi @mikededo 馃憢
Thanks for opening an issue!
You can definitely choose to create generic base states which you reuse if you feel it makes sense for your use case. The nice thing is the bloc library has no opinions about how you choose to model your events and states -- it's completely up to you 馃槃
The main downside of doing that is all of your states/events will be the same so from a logging/analytics perspective it might be tricky to figure out what's going on but no harm in giving it a shot and seeing how it feels 馃憤
Closing for now but feel free to comment with additional questions and I'm happy to continue the conversation.
Something else to consider @mikededo is that you'll have to keep passing the generic type everywhere. So whatever boilerplate you feel you're removing by having a generic state class, you might end up gaining it back somewhere else.
The main downside of doing that is all of your states/events will be the same so from a logging/analytics perspective it might be tricky to figure out what's going on but no harm in giving it a shot and seeing how it feels 馃憤
Oh, I did not think about that. Everytime a the BlocObserver printed a transition, it would write the same for all bloc whic implement that state, wouldn'nt it?
@RollyPeres Yes, that is something I will take into account! 馃槃
A possiblity of knowing which type is, would be by knowing what runType is the GenereicState using.
For instance, in the StateLoaded class, instead of:
@override
String toString() => 'StateLoaded(items: $items)';
It could be:
@override
String toString() => '${this.runtimeType}(items: $items)';
I don鈥檛 think runtimeType will be human readable in release mode so it won鈥檛 be that useful outside of local debugging.