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

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

StreamProviderを使えば非同期処理(Stream型)によるデータを取得できます。FutureProviderは単体のデータを取得するのに対し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をラップする必要があります。

StreamProviderの使い方

定義

final streamProvider = StreamProvider.autoDispose((ref) => Stream.periodic(
      Duration(milliseconds: 300),
      (count) => count,
    ));

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

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

データ取得

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

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

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

final stream = ref.watch(streamProvider);

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

stream.when(
  loading: () => CircularProgressIndicator(),
  data: (value) => Text(
    value.toString(),
    style: TextStyle(fontSize: 30),
  ),
  error: ((error, stackTrace) => Text('Error: $error')),
),

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

Consumerでデータ取得

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

サンプルコード

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

final streamProvider = StreamProvider.autoDispose((ref) => Stream.periodic(
      Duration(milliseconds: 300),
      (count) => count,
    ));

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

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

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

一緒に読みたい

参考

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