skip to Main Content

Creating a workout app in flutter.

The models look like this,

class Workout extends Equatable {
  String name;
  final String description;
  final String type;
  final int? id;
  List<Exercise> exercises;
}

class Exercise extends Equatable {
  String name;
  final String description;
  final int? id;
  List<Set> sets;
}

class Set extends Equatable {
  String name;
  final int reps;
  final int weight;
  final int? id;

}

Here’s the thing, I have WorkoutBloc, ExerciseBloc, SetBloc. And then I give them the corresponding models. (for example, Workout bloc holds a ‘workout’ object)

The problem is, when now completing a set through SetBloc. The data in the other blocs are now expired.

What do I do?

Do I use a single bloc, which would result in a giant mess and probably worse performance.

Should I remove the nested structure altogether and rely on ID’s instead. Basically flattening everything?

Should I use listeners to synchronise them?

What can I do?

2

Answers


  1. make all models in one bloc’s state then you can simply use all model values at same time.

    Login or Signup to reply.
  2. First of all, consider using cubits over blocs. In your example you dont have to store data about what event triggered the change or what the flow of states was, hence its good idea to use simpler tool that will do just what you need, a cubit.

    Cubits work just as blocs with the difference that we dont use events to trigger logic inside components, we just directly call methods on cubit and pass required data as paramethers instead as event variables.

    Do not worry about performance. It wont really matter if you use one cubit to store all the data for entire workout or you use three cubits that will hold data that they are responsible for. Things like this are way too small in memory to make a difference.

    If you merge these cubits into one it will be easier to use when mapping state to UI. You will be able to easly iterate thru exercises and sets to build elements. It can be cleaner and easier to read the code since you will be providing and reading only one cubit. You wont have to worry about that if you modify set (eg reps) or exercise (eg name) you will have to update other cubits.

    The cons are however, that you will write a lot of not so good looking code inside cubits when, say, modifying rep if you wont use any library that would help you easly copy collections instead of modyfing them, like KtDart does, since states should always be immutable.

    Pros of three cubits each for one type of data feels easier at first and yes, you do separate the data from each other what some may call a good practice, but from my experience it wont help you. You will have to maintain 3 cubits, you will have to make sure if you update exercise to update set inside SetsCubit, more that that the idea of Cubit holding only one set is just useless since you want to display a lot of sets at the same time.

    Also, consider using freezed over Equatable. It will generate copyWith methods for you.
    You can create freezed class for your purposes like this:

    @freezed
    class WorkoutState with _$WorkoutState {
      factory WorkoutState.initial() = _Initial;
      factory WorkoutState.loading() = _Loading;
      factory WorkoutState.error() = _Error;
      factory WorkoutState.loaded({
        required String name,
        required String description,
        required String type,
        @Default(-1) int? id,
        required List<Exercise> exercises,
      }) = _Loaded;
    }
    

    Inside cubit methods you will write a lot of copyWith‘s but I strongly believe it will be easier to use in views and this is going to be the price for its usability once you write it. You can always add some helper methods that will help you drill from exercise to the set you want to modify increasing readability.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search