State classes
- Flutter course
- Advanced
- Lesson 8/69
- 4 min
Model UI state with state classes.
What are state classes?
State classes are immutable objects that model the current state of the interface. Each distinct UI state is expressed as a separate state class: loading, success, error, and so on. This allows safe state checks like if (state is LoginSuccess).
abstract class LoginState {}
class LoginLoading extends LoginState {}
class LoginSuccess extends LoginState {
final String user;
LoginSuccess(this.user);
}Abstract state and subclasses
Deriving states from an abstract class groups common behavior and makes state checks safer. When you define every possible state as a separate class, you handle each case individually with switch or if (state is ...). This makes it harder to miss a case and keeps the code readable.
abstract class LoginState {}
class LoginInitial extends LoginState {}
class LoginLoading extends LoginState {}
class LoginSuccess extends LoginState {}Practice Write a LoginBloc and state classes
Define LoginEvent and LoginSubmittedEvent. Write the LoginState abstract class with LoginLoading and LoginSuccess (holds a username) subclasses. LoginBloc should start with LoginLoading and its LoginSubmittedEvent handler should emit LoginSuccess('Ayşe'). In main, trigger the event, wait, and print the username on success.
Starter code
import 'package:bloc/bloc.dart';
// LoginEvent ve LoginSubmittedEvent sınıflarını tanımla
// LoginState soyut sınıfını ve alt sınıflarını tanımla
// LoginLoading ve LoginSuccess (kullanıcı adı tutar)
class LoginBloc extends Bloc<LoginEvent, LoginState> {
LoginBloc() : super(LoginLoading()) {
// event işleyici ekle
}
}
void main() async {
// oluştur, event ekle, bekle, durumu kontrol et
}Sample solution
import 'package:bloc/bloc.dart';
abstract class LoginEvent {}
class LoginSubmittedEvent extends LoginEvent {}
abstract class LoginState {}
class LoginLoading extends LoginState {}
class LoginSuccess extends LoginState {
final String user;
LoginSuccess(this.user);
}
class LoginBloc extends Bloc<LoginEvent, LoginState> {
LoginBloc() : super(LoginLoading()) {
on<LoginSubmittedEvent>((event, emit) =>
emit(LoginSuccess('Ayşe')));
}
}
void main() async {
final bloc = LoginBloc();
bloc.add(LoginSubmittedEvent());
await Future.delayed(Duration(milliseconds: 10));
final state = bloc.state;
if (state is LoginSuccess) {
print(state.user);
}
}Expected output
Ayşe
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 How should state classes be designed?
- Immutable, with a separate class per state Correct answer
- No state class, use a Map instead
- Mutable, with flags inside a single class
- A separate state class for each widget
Explanation: States should be immutable and each possible state should be modeled with its own class; a single class with flags is error-prone.
2 Define a state class
class LoginSuccess extends ____ {
final String user;
LoginSuccess(this.user);
}
class LoginSuccess extends LoginState {
final String user;
LoginSuccess(this.user);
}
Explanation: LoginSuccess is a state, so it derives from the base state class LoginState; not from Bloc or Event.
3 State parts
| Term | Meaning |
|---|---|
abstract class LoginState |
Base state class |
class LoginLoading extends |
Loading state |
final String user |
State data |
if (state is LoginSuccess) |
State check |