AsyncNotifiterとは
AsyncNotifiterはRiverpod において API通信などの非同期処理を前提にした状態管理クラスです。
特徴としては画面を開いたら API を呼んでデータを表示する形の画面があるのですが、このような処理を一番シンプルに書くための仕組みです。
なぜAsyncを使うのか
アプリ開発では、プロフィールの取得や投稿一覧・通知一覧の読み込み、初期データのロード、サーバーの状態取得など、非同期処理(async / await)を行う場面が非常に多くあります。
これらの処理では必ず「通信中のローディング状態」「データ取得成功」「エラー発生」という状態遷移が発生しますが、AsyncNotifier を使うことで、これらの状態を開発者が個別に管理する必要がなくなり、ローディング・成功・エラーの管理を自動的に行うことができます。
AsyncNotifierを使えばいい場合
-
画面表示と同時に API を呼びたいとき
-
サーバーからデータを取得する処理
-
初期ロードが必要な画面
-
DB / ネットワーク通信
機能を例として挙げると
-
プロフィール画面
-
投稿一覧画面
-
通知一覧画面
などがあります。
使わない方がいいケース
-
ボタンの ON / OFF
-
タブの選択状態
-
フォーム入力値
-
一時的な UI 状態
こんな機能では StateNotifier や StateProvider が適切です。
AsyncNotifierを使った典型的な流れ
-
画面が開かれる
-
provider が watch される
-
build() が自動実行される
-
API が呼ばれる
-
状態が loading → data / error に変わる
-
UI が自動で更新される
例コード
///UI画面
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class ProfilePage extends ConsumerWidget {
const ProfilePage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final profileAsync = ref.watch(profileProvider);
return Scaffold(
appBar: AppBar(title: const Text('プロフィール')),
body: profileAsync.when(
loading: () => const Center(
child: CircularProgressIndicator(),
),
error: (e, _) => Center(
child: Text('エラーが発生しました'),
),
data: (profile) => Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('名前: ${profile.name}'),
Text('メール: ${profile.email}'),
],
),
),
),
);
}
}
///provider
import 'package:flutter_riverpod/flutter_riverpod.dart';
final profileRepositoryProvider =
Provider((ref) => ProfileRepository());
final profileProvider =
AsyncNotifierProvider<ProfileNotifier, Profile>(
ProfileNotifier.new,
);
class ProfileNotifier extends AsyncNotifier<Profile> {
@override
Future<Profile> build() async {
final repository = ref.read(profileRepositoryProvider);
// 🔽 画面を開いた瞬間に API 実行
return repository.fetchProfile();
}
}
///Repository
class Profile {
final String name;
final String email;
Profile({
required this.name,
required this.email,
});
}
class ProfileRepository {
Future<Profile> fetchProfile() async {
await Future.delayed(const Duration(seconds: 1)); // 仮のAPI
return Profile(
name: '山田 太郎',
email: 'taro@example.com',
);
}
}
説明
- ProfilePage 画面が開ける
画面遷移によって ProfilePage が初めてビルドされ、この時点で UI が profileProvider を利用する準備が整う。まだ API は呼ばれておらず、あくまで画面が表示されるトリガーとなる段階である。
- profileProviderをwatch
ref.watch(profileProvider) が実行され、UI が profileProvider に依存していることが Riverpod に登録される。これにより、provider がまだ生成されていない場合は新しく作成され、以降の状態変更を UI が自動的に受け取れるようになる。
- AsyncNotifierのbuild() を実行
AsyncNotifier の build() を実行
provider の初期化に伴い AsyncNotifier が生成され、内部で build() が自動的に呼び出される。この時点で状態は AsyncLoading となり、非同期処理の開始が宣言される。
- APIを呼び出す
build() の中で Repository を通じて API 通信が実行され、サーバーからデータの取得が行われる。通信中は AsyncLoading 状態が維持され、UI にはローディング表示が反映される。
- loading → data状態に変わって UIが自動更新される
API のレスポンスが正常に返ると、状態は AsyncData に自動的に更新される。これを検知した UI は再ビルドされ、ローディング表示から実際のデータ表示へと切り替わる。