So I have a Flutter app with Bloc for state mangement. I want to keep a list of users in Bloc so I can access it from different places in the app. But as it is now I pass this list of users to every state. Can I somehow avoid this boilerplate code?
Here is an example of my Bloc State:
@immutable
abstract class UsersState {
final List<User> users;
final User? user;
const UsersState({required this.users, required this.user});
}
class UsersInitial extends UsersState {
UsersInitial() : super(users: [], user: null);
}
class UsersLoadedState extends UsersState {
const UsersLoadedState({required List<User> users, required User? user})
: super(users: users, user: user);
}
class UsersPendingState extends UsersState {
const UsersPendingState({List<User> users = const [], User? user})
: super(users: users, user: user);
}
class UsersErrorState extends UsersState {
final String message;
const UsersErrorState(
{required List<User> users, required User? user, required this.message})
: super(users: users, user: user);
}
class FriendAddedState extends UsersState {
const FriendAddedState({required List<User> users, required User? user})
: super(users: users, user: user);
}
In this example I don't want to have to pass list of users to FriendAddedState. And here is how it looks in Bloc:
else if (event is AddFriend) {
emit(FriendAddPending(users: users, user: user));
final result = await usecases.addFriend(event.friendId);
result.fold((error) {
emit(UsersErrorState(
users: users, user: user, message: error.message));
}, (success) {
user = success;
emit(FriendAddedState(users: users, user: user));
});
}
You don't have to define users
and user
in UserState
if you don't need them in all the bloc states. You could just define them in UsersLoadedState
FriendAddedState
like this:
@immutable
abstract class UsersState {
const UsersState();
}
class UsersInitial extends UsersState {
const UsersInitial();
}
class UsersLoadedState extends UsersState {
const UsersLoadedState({
required this.users,
required this.user,
});
final List<User> users;
final User? user;
}
class UsersPendingState extends UsersState {
const UsersPendingState();
}
class UsersErrorState extends UsersState {
final String message;
const UsersErrorState({required this.message});
}
class FriendAddedState extends UsersState {
const FriendAddedState({
required this.users,
required this.user,
});
final List<User> users;
final User? user;
}
[Recommended] if you want to access user in every state of bloc, you can use a single class for your bloc state and an enum to define its state:
@immutable
class UsersState {
final List<User> users;
final User? user;
final String? message;
final UserStatus status;
const UsersState({
required this.status,
required this.users,
this.user,
this.message,
});
const UsersState.initial()
: status = UserStatus.initial,
users = const [],
user = null,
message = null;
UsersState copyWith(
List<User>? users,
User? user,
String? message,
UserStatus? status,
) {
return UsersState(
status: status ?? this.status,
users: users ?? this.users,
message: message ?? this.message,
user: user ?? this.user,
);
}
}
enum UserStatus {
initial,
loaded,
pending,
error,
friendAdded,
}
then in your bloc class, anywhere you wanted to emit new state, use state.copyWith()
!