0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AsyncNotifiterとは

AsyncNotifiterはRiverpod において API通信などの非同期処理を前提にした状態管理クラスです。

特徴としては画面を開いたら API を呼んでデータを表示する形の画面があるのですが、このような処理を一番シンプルに書くための仕組みです。

なぜAsyncを使うのか

アプリ開発では、プロフィールの取得や投稿一覧・通知一覧の読み込み、初期データのロード、サーバーの状態取得など、非同期処理(async / await)を行う場面が非常に多くあります。

これらの処理では必ず「通信中のローディング状態」「データ取得成功」「エラー発生」という状態遷移が発生しますが、AsyncNotifier を使うことで、これらの状態を開発者が個別に管理する必要がなくなり、ローディング・成功・エラーの管理を自動的に行うことができます。

AsyncNotifierを使えばいい場合

  • 画面表示と同時に API を呼びたいとき

  • サーバーからデータを取得する処理

  • 初期ロードが必要な画面

  • DB / ネットワーク通信

機能を例として挙げると

  • プロフィール画面

  • 投稿一覧画面

  • 通知一覧画面

などがあります。

使わない方がいいケース

  • ボタンの ON / OFF

  • タブの選択状態

  • フォーム入力値

  • 一時的な UI 状態

こんな機能では StateNotifier や StateProvider が適切です。

AsyncNotifierを使った典型的な流れ

  1. 画面が開かれる

  2. provider が watch される

  3. build() が自動実行される

  4. API が呼ばれる

  5. 状態が loading → data / error に変わる

  6. 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',
    );
  }
}

説明

  1. ProfilePage 画面が開ける

画面遷移によって ProfilePage が初めてビルドされ、この時点で UI が profileProvider を利用する準備が整う。まだ API は呼ばれておらず、あくまで画面が表示されるトリガーとなる段階である。

  1. profileProviderをwatch

ref.watch(profileProvider) が実行され、UI が profileProvider に依存していることが Riverpod に登録される。これにより、provider がまだ生成されていない場合は新しく作成され、以降の状態変更を UI が自動的に受け取れるようになる。

  1. AsyncNotifierのbuild() を実行

AsyncNotifier の build() を実行
provider の初期化に伴い AsyncNotifier が生成され、内部で build() が自動的に呼び出される。この時点で状態は AsyncLoading となり、非同期処理の開始が宣言される。

  1. APIを呼び出す

build() の中で Repository を通じて API 通信が実行され、サーバーからデータの取得が行われる。通信中は AsyncLoading 状態が維持され、UI にはローディング表示が反映される。

  1. loading → data状態に変わって UIが自動更新される

API のレスポンスが正常に返ると、状態は AsyncData に自動的に更新される。これを検知した UI は再ビルドされ、ローディング表示から実際のデータ表示へと切り替わる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?