このサイトは、特にやりたいこともなく無気力に生きる汚い中年おじさんデザイナー佐藤文彦のポートフォリオサイトです。
応援よろしくお願いします。

FlutterのRiverpodでProviderを学ぶ

2022/03/10

Flutter用のRiverpodをインストール

Riverpodのパッケージにはいくつか種類があり、今回はFlutter用のflutter_riverpodを利用したいと思います。

flutter pub add flutter_riverpod

アプリケーション内でProviderを利用できるようにする

main.dartのアプリルートで以下のようにMyApp()ProviderScopeでラップすることで、アプリケーション内でProviderを利用できるようになります。

void main() {
  - runApp(const MyApp());
  + runApp(ProviderScope(child: const MyApp()));
}

Riverpodの表示用Widget

  • Consumer ・・・Widgetに埋め込む
  • ConsumerWidget ・・・StatelessWidgetのRiverpod版
  • ConsumerStatefulWidget ・・・StatefulWidgetのRiverpod版

RiverpodのProvider

  • Provider ・・・ 定数
  • StateProvider ・・・ 変数
  • ScopedProvider・・・出力を指定することができる
  • StateNotifierProvider・・・変数 + メソッド
  • FutureProvider・・・Future版(あとでデータを取ってきてから参照するなど)
  • StreamProvider・・・Stream版(snapshotなどを利用してFirebaseなどからデータをとってくるのよく使われる)
  • ChangeNotifierProvider・・・ChangeNotifierを使う

Riverpodの表示方法

  • watch ・・・状態変更でWidgetを更新する場合に使用する
  • read・・・状態変更でWidgetを更新しない場合に使用する
  • select ・・・データ内の特定の値が変更したときのみWidgetを更新する場合に使用する

Providerを使ってみる

最も基本的なProvideの利用方法です。 グローバル変数として宣言でき、主に定数のように利用するProviderです。

ConsumerWidgetを継承する

通常のWidgetでは、Providerを利用することができない為、ConsumerWidgetを継承するように変更します。
build関数の第2引数には、providerにアクセスするためのWidgetRef refを追加します。
refを使ってProviderの値を操作します。

class MyHomePage extends ConsumerWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  
  Widget build(BuildContext context, WidgetRef ref) {
  ...

Providerを定義する

まずは、以下のようにProviderを定義。
引数のrefを利用して他のProviderを読み込むことも可能です。
refを利用しない場合は、_として省略しても良いです。

lib/provider.dartを作成。

import 'package:flutter_riverpod/flutter_riverpod.dart';

final titleProvider = Provider<String>((ref) {
  return 'Titleだよ';
});

Providerにアクセスするには、ref.watchを利用します。

利用先のdartファイル。

import 'package:hogehoge/provider.dart';

class TitleView extends ConsumerWidget {
  const HomeView({Key? key}) : super(key: key);

  
  Widget build(BuildContext context, WidgetRef ref) {
    final title = ref.watch(titleProvider);
    return Text(title);
  }
}

Providerの書き方メモ

refを省略する場合。

final messageProvider = Provider<String>((_) {
  return 'メッセージだよ';
});

他のProviderを参照する場合。

final hogeProvider = StateProvider<String>((ref) => 'hogeProvider');
final anotherProvider = Provider<String>((ref) => ref.watch(hogeProvider));

StateProviderを使ってみる

StateProviderは値を取得する以外にも、外部から値の変更が可能です。

lib/provider.dartを作成。

import 'package:flutter_riverpod/flutter_riverpod.dart';

final counterProvider = StateProvider<int>((ref) {
  return 0;
});

表示する

class CounterView extends ConsumerWidget {
  const HomeView({Key? key}) : super(key: key);

  
  Widget build(BuildContext context, WidgetRef ref) {
    final counter = ref.watch(counterProvider).toString; // int型なのでキャストしている
    return Text(counter);
  }
}

変更する

変更する場合は、

ref.watch(プロバイダ.state).state =;

もしくは、こちらで変更。

ref.watch(プロバイダ.notifier).state =;

もしくは、こちらで変更。

ref.watch(プロバイダ.state).update((state) =>) ;
class MyHomePage extends ConsumerWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: Text('タイトル'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(onPressed: () {
              // カウンターをインクリメントする
              ref.watch(counterProvider.notifier).state ++;
            }, child: Icon(Icons.add)),
            Text(ref.watch(counterProvider).toString()), // Providerを取得して表示
          ],
        ),
      ),
    );
  }
}

Widgetからrefを取得する

通常のWidgetでは、Providerを利用することができない為、以下の方法で利用できるようにします。

ConsumerWidgetを継承する

StatelessWidgetConsumerWidgetに置き換え、
build()の第二引数にWidgetRef refをわたします。

ref.watch(プロバイダー名)でProviderの値を取得します。

class MyHomePage extends ConsumerWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: Text('タイトル'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(onPressed: () {
              // カウンターをインクリメントする
              ref.watch(counterProvider.state).update((state) => state + 1);
            }, child: Icon(Icons.add)),
            Text(ref.watch(counterProvider).toString()), // Providerを取得して表示
          ],
        ),
      ),
    );
  }
}

第2引数のrefを利用してProviderを監視します。

カテゴリ

新規記事