【Flutter/Riverpod】FutureProviderで状態管理|非同期処理によるデータ取得

今回はRiverpodのFutureProviderを使った状態管理を行なっていきます。

FutureProviderを使えば非同期処理(Future型)によるデータを取得できます。Streamによるデータを取得する場合はStreamProviderを使用します。

\ 世界最大級のオンライン学習サービス /

目次

事前準備|flutter_riverpodの導入

flutter pub add flutter_riverpod
import 'package:flutter_riverpod/flutter_riverpod.dart';

flutter_riverpodを導入します。

ProviderScopeでウィジェットツリーをラップ

void main() => runApp(ProviderScope(child: MyApp()));

Riverpodのプロバイダを使用するにはProviderScopeでウェジェットツリーのルート(先祖)となるWidgetをラップする必要があります。

FutureProviderの使い方

定義

final futureHelloWorld = FutureProvider((ref) async {
  await Future.delayed(const Duration(seconds: 3));
  return 'Hello World';
});

FutureProviderでは非同期処理によるデータを返り値にできます。

今回はグローバル変数として定義しています。(記事下にサンプルコードあり)

データ取得

class MyApp extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final future = ref.watch(futureHelloWorld);

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('FlutterZero')),
        body: Center(
          child: future.when(
            loading: () => CircularProgressIndicator(),
            data: (value) => Text(value.toString()),
            error: ((error, stackTrace) => Text('Error: $error')),
          ),
        ),
      ),
    );
  }
}

StatelessWidgetでプロバイダの値を取得したい場合はConsumerWidgetを継承します。StatefulWidgetの場合はConsumerStatefulWidgetを継承します。

final future = ref.watch(futureHelloWorld);

ref.watchFutureProviderの値を取得します。またFutureProviderの状態(ステート)を監視し、状態が更新する度にビルドし直します。

future.when(
  loading: () => CircularProgressIndicator(),
  data: (value) => Text(value.toString()),
  error: ((error, stackTrace) => Text('Error: $error')),
),

非同期処理ではAsyncValueを使用してローディング中またはエラーが発生した場合の値も返す必要があります。先ほど定義したfuturewhenを使用して状態別にコールバック関数で返り値を指定します。

Consumerでデータ取得

ConsumerWidgetまたはConsumerStatefulWidgetを継承せずにConsumerで値を取得することも可能です。

サンプルコード

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final counterProvider = StateProvider((ref) => 0);

void main() => runApp(ProviderScope(child: MyApp()));

class MyApp extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('FlutterZero')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  IconButton(
                    icon: Icon(Icons.remove),
                    onPressed: () => ref.read(counterProvider.notifier).update((state) => ++state),
                  ),
                  Text(
                    count.toString(),
                    style: TextStyle(fontSize: 30),
                  ),
                  IconButton(
                    icon: Icon(Icons.add),
                    onPressed: () => ref.read(counterProvider.notifier).update((state) => ++state),
                  ),
                ],
              ),
              ElevatedButton(
                onPressed: () {
                  ref.read(counterProvider.notifier).state = 0;
                },
                child: Text('Reset'),
              )
            ],
          ),
        ),
      ),
    );
  }
}

一緒に読みたい

参考

  • URLをコピーしました!
目次