以前書いた記事でBLoCは複数のStateを順次通知するような挙動ができると書きました。
これを説明する良いチュートリアルがあったので紹介します。
チュートリアルは[こちら]です。(https://resocoder.com/2020/08/04/flutter-bloc-cubit-tutorial/)
サンプルアプリケーションの動き
このアプリケーションの動きは以下のようになります。
- TextFieldに都市名を入力する
- BlocまたはCubitが都市名入力を受け取り以下の順にStateを返す
- Repository(ダミー)が気温データを取得中(1秒間)はLoading
- 気温データを取得後はLoaded
Loading → Loaded というようにStateが変化します。
実際のコード: Cubit
Cubitのコードは以下のようになっています。
getWeather()
メソッド内でデータ取得前後でStateをemit()
をしています。
class WeatherCubit extends Cubit<WeatherState> {
final WeatherRepository _weatherRepository;
WeatherCubit(this._weatherRepository) : super(WeatherInitial());
Future<void> getWeather(String cityName) async {
try {
// ここでStateを連続して通知しています。
emit(WeatherLoading());
final weather = await _weatherRepository.fetchWeather(cityName);
emit(WeatherLoaded(weather));
} on NetworkException {
emit(WeatherError("Couldn't fetch weather. Is the device online?"));
}
}
}
実際のコード: Bloc
これをBlocで書くと以下のようになります。
mapEventToState()
内でデータ取得前後でStateをyieldしています。
class WeatherBloc extends Bloc<WeatherEvent, WeatherState> {
final WeatherRepository _weatherRepository;
WeatherBloc(this._weatherRepository) : super(WeatherInitial());
@override
Stream<WeatherState> mapEventToState(
WeatherEvent event,
) async* {
if (event is GetWeather) {
try {
// ここでStateを連続して通知しています。
yield WeatherLoading();
final weather = await _weatherRepository.fetchWeather(event.cityName);
yield WeatherLoaded(weather);
} on NetworkException {
yield WeatherError("Couldn't fetch weather. Is the device online?");
}
}
}
}
CubitではなくBlocを使う方が一般的だと思います。この方法はBlocパターンではよく使うので把握しておくとよいと思います。
View側のコード
BlocBuilder(listenerを併用する場合はBlocConsumer)にて表示するWidgetを切り替えています。
ローディング中はCircularProgressIndicator()
を表示しています。
その他の補足ポイント
== と hashCodeをオーバーライドしている
このサンプルではStateとEventにEquatable
を用いていません。
なのでこちらの記事で説明したように ==
と hashCode
をオーバーライドしています。
以上です。わかりやすいサンプルなのでぜひ参考にしてみてください。