RiverpodでStateNotifierを使って状態を扱う
最終更新日:2024-08-25
RiverpodのStateNotifierを使うと状態を扱うことができます。Androidで言うところのViewModelっぽいものを作るときに便利そうです。
StateNotifierを継承したクラスを作る
例としてログイン画面の状態を扱う LoginViewModel
を作ってみます。状態部分は sealed class
にしてみます。
class LoginViewModel extends StateNotifier<UiState> {
final AccountRepository accountRepository;
LoginViewModel({
required this.accountRepository,
}) : super(const Idle());
void login(String email, String password) async {
state = const InProgress();
try {
final account = await accountRepository.login(email, password);
state = Success(account: account);
} catch (e) {
state = Error(e: e);
}
}
}
// 状態を表すクラス
sealed class UiState {
const UiState();
}
class Idle extends UiState {
const Idle();
}
class InProgress extends UiState {
const InProgress();
}
class Success extends UiState {
final Account account;
Success({required this.account});
}
class Error extends UiState {
final Object e;
Error({required this.e});
}
StateNotifierProviderを作る
StateNotifierProvider
を使って、LoginViewModel
の作り方を指示します。 WidgetRef
があるので依存するオブジェクトを read()
で取得することもできます。
final _viewModelProvider = StateNotifierProvider<LoginViewModel, UiState>((ref) {
final accountRepository = ref.read(accountRepositoryProvider);
return LoginViewModel(
accountRepository: accountRepository,
);
});
watchで状態を取得する
ConsumerWidget
の build()
の中で ref.watch()
を使うと状態を取得・監視することができます。状態が変化したタイミングで再度 build()
が実行されます。
class LoginScreen extends ConsumerWidget {
@override
void build(BuildContext context, WidgetRef ref) {
final uiState = ref.watch(_viewModelProvider);
return switch (uiState) {
}
}
}
StateNotifierを取得する
ref.read(provider.notifier)
で、 StateNotifier
を取得することができます。状態更新のためのメソッドを呼びたいときに使います。
class LoginScreen extends ConsumerWidget {
@override
void build(BuildContext context, WidgetRef ref) {
// 取得する
final viewModel = ref.read(_viewModelProvider.notifier);
...
ElevatedButton(onPressed: () {
viewModel.login();
}, child: const Text("Login"));
}
}