1. 概要
上記前回のブログでは「Riverpod」の「StateProvider」を使ったCounterの状態管理についてでした。
「StateProvider」は「enumや数値」などシンプルなステートを管理するのに適しているようです。
StateProvider は外部から変更が可能なステート(状態)を公開するプロバイダです。 StateNotifierProvider の簡易版であり、ステートの管理にわざわざ StateNotifier クラスを定義するほどではない場合にご利用いただけます。
https://riverpod.dev/ja/docs/providers/state_provider
今回は「StateNotifierProvider」を使い、Counterの状態管理をする内容についてです。
今回も前回と結果は同じでシンプルなステートを管理する内容なので、結果的には「StateProvider」を使った方が良いと思われますが、ここでは「StateNotifierProvider」を使って開発する例として見て頂ければと思います。
StateNotifierProvider は StateNotifier(Riverpod が依存する state_notifier パッケージのクラス)を監視し、公開するためのプロバイダです。 この StateNotifierProvider および StateNotifier は、ユーザ操作などにより変化するステート(状態)を管理するソリューションとして Riverpod が推奨するものです。
https://riverpod.dev/ja/docs/providers/state_notifier_provider
※今回は下記の例で、前回と同じ結果になるように構成してます。
- Riverpod
- StatelessWidget / ConsumerWidget
- アプリ起動中に状態が変化しない
- StateNotifierProvider / ProviderScope
- StatelessWidget / ConsumerWidget
対象としては開発を1年程やってて自分で最初から開発してみたい方になります。そのため細かい用語などの説明はしません。
2. StateNotifierProvider
2-1. プロジェクトを作成
2-2. Dependencyのインストール
flutter pub add flutter_riverpod
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
flutter_riverpod: ^1.0.4
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
2-3. ソースコード
- main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_demo_with_model/models/counter.dart';
import 'package:riverpod_demo_with_model/notifiers/counter_notifier.dart';
import 'package:riverpod_demo_with_model/views/home.dart';
final counterProvider =
StateNotifierProvider<CounterNotifier, CounterData>((ref) {
return CounterNotifier();
});
void main() {
runApp(const ProviderScope(
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
- views/home.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_demo_with_model/main.dart';
class MyHomePage extends ConsumerWidget {
const MyHomePage({Key? key, required String title}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final data = ref.watch(counterProvider);
final counterNotifier = ref.read(counterProvider.notifier);
return Scaffold(
appBar: AppBar(
title: const Text('Riverpod example'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Center(
child: Text(
data.counter.toString(),
style: Theme.of(context).textTheme.headline4,
),
),
ElevatedButton(
onPressed: () => counterNotifier.plus(), child: const Text('+')),
ElevatedButton(
onPressed: () => counterNotifier.minus(), child: const Text('-')),
],
),
);
}
}
- models/counter.dart
import 'package:flutter/material.dart';
@immutable
class CounterData {
const CounterData({required this.counter});
final int counter;
}
- notifiers/counter_notifier.dart
// ignore_for_file: avoid_print
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_demo_with_model/models/counter.dart';
class CounterNotifier extends StateNotifier<CounterData> {
CounterNotifier() : super(const CounterData(counter: 0));
void plus() {
state = CounterData(counter: state.counter + 1);
print('plus=${state.counter}');
}
void minus() {
state = CounterData(counter: state.counter - 1);
print('minus=${state.counter}');
}
}
2-4. 結果
2-5. 解説
「ProviderScope」を使い、状態管理の対象を指定します。
状態を管理するためのプロバイダとして「StateNotifierProvider」を使います。
プロバイダを利用するためには「ref」を取得する必要があるので「ConsumerWidget」を継承します。
- プロバイダの利用方法 | Riverpod
- ref.watch():プロバイダの値を取得した上で、その変化を監視する。値が変化すると、その値に依存するウィジェットやプロバイダの更新が行われる。
- ref.read():プロバイダの値を取得する(監視はしない)。クリックイベント等の発生時に、その時点での値を取得する場合に使用できる。
3. 参考
投稿者プロフィール
-
開発好きなシステムエンジニアです。
卓球にハマってます。