Flutter - Riverpod
インストール
- Flutter + flutter_hooks で使う場合 =>
hooks_riverpod
- Flutter で使う場合 =>
flutter_riverpod
- Flutter は使わず Dart のみの場合 =>
riverpod
最小構成
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
// "hello world"という値を保持するプロバイダを作成する。
final helloWorldProvider = Provider((_) => 'Hello world');
void main() {
runApp(
// ウィジェットが値を読み出せるように、
// アプリ全体をProviderScopeでラップする。
// すべてのプロバイダはここで生息する。
ProviderScope(
child: MyApp(),
),
);
}
// flutter_hooksのHookConsumerWidgetを使用している点に注意
class MyApp extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// HookConsumerWidgetのおかげで、
// `ref.watch()`を使って値を読み出せる。
final String value = ref.watch(helloWorldProvider);
return MaterialApp(
home: Scaffold(body: Text(value)),
);
}
}
Provider とは
- Provider は下記の2つを実現するためのオブジェクト
- state をカプセル化する
- state を listen できるようにする
- Providers を使うメリット
- state を複数の場所で使える
- 複数の state を簡単に組み合わせられる
- パフォーマンスの最適化が可能
- テストが容易
- Logging や pull-to-refresh などの先進機能との統合が容易
Provider の作成
final myProvider = Provider((ref) {
return MyValue();
});
- プロバイダ自体は immutable でなければならないので
final
で宣言する Provider
が最も基本的なプロバイダ。他にもStreamProvider
やStateNotifierProvider
などがある。- コールバック関数は常に
ref
を受け取る。ref
は以下の用途に使う。- 他の Provider の値を取得する
- Destroy 時に特定の処理を行う(たとえばストリームを閉じる処理など)
Provider Modifiers
- Modifier を使うと、少し機能を追加したり変更した Provider を作成できる。
- Modifier どの種類の Provider でも利用可能。
- 今のところ以下の2種類しかない。
final myAutoDisposeProvider = StateProvider.autoDispose<int>((ref) => 0);
final myFamilyProvider = Provider.family<String, int>((ref, id) => '$id');
Provider を読み取る
Provider の値を読む方法はいくつかある。
なにを読み取るか決める
読み取れる値の種類は複数ある場合がある。たとえば StreamProvider を使ったとき、取得できる値の種類は3つある。詳しくはこちら。
Stream
として受け取るFuture
として受け取るAsyncValue
(riverpod の型)として受け取る
ウィジェットの中で読み取る
ConsumerWidget
を使う方法
StatelessWidget
の代わりにConsumerWidget
を使う。- 注意:
watch
メソッドを非同期に呼び出してはいけない。例えばonPressed()
の中など。その場合は後述のcontext.read(myProvider)
を使う。
class Home extends ConsumerWidget {
@override
Widget build(context, ref) {
int count = ref.watch(counterProvider).state;
return Scaffold(/*...*/);
}
}
Consumer
を使う方法
- state の変更時に全体が再描写されるのを防ぎたいときに使う
- 下記の場合、state が更新されても Consumer の外側は再描写されない
Consumer(
builder: (context, ref, child) {
int count = ref.watch(counterProvider).state;
return Text('$count');
},
),