状態管理って、なんか今ひとつわかんねー。いや、言ってることは理屈ではわかるんだけどね。実装に結びつかないというか、じゃあ俺のしたいことはどうしたらできるのよ、っていうのがよくわかっていない。
そこで、Riverpodで状態管理を学んでみるよ。馬鹿になって学べ。
基本的にRiverpodの公式に書いてあることから学んでいくよ。
1.環境はこんな感じ
Riverpodはdartのみ、flutterのみ、flutter+flutter_hooksの環境で使えるよ。
おいらはちょっと臆病者だから、flutter_hooks使って深みにはまるのが怖いから、flutterのみの環境で使ってみるよ。
ちなみにflutterのバージョンは3.0.5だ。
2.インストールする
flutterでパッケージをインストールするときは、pubspec.yamlにインストールするパッケージを書けばいいよ。簡単だね。
dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^2.1.3 ←これを追加
修正したpubspec.yamlを保存したら、flutter pub getコマンドを実行すると、パッケージが取り込まれるよ。VSCodeだと、保存したときに自動でコマンド実行されるみたいだけど、信用できなきゃ自力でコマンド投入だ。
これでRiverpodが使えるようになるよ。
3.Hello Worldを出してみる
Riverpodをインストール出来たら、みんな大好きHello Worldを出してみるよ。
公式にもHello Worldを出しているサンプルソースが出ているけど、mainしか使ってないのでなんかやった感がない。ここはひとつ、こちらもみんな大好きflutterのプロジェクト作成時にデフォルトで作られるカウンタアプリを改造してHello Worldを出してみるよ。
ちなみに先人がデフォルトのカウンタアプリをRiverpod仕様に改造した事例があったよ。とても参考になりました。あざす!
早速ソースをのっけるよ。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final helloProvider = StateProvider<String>((ref) => ' ');
String statement = '';
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: ' Demo Home Page'),
);
}
}
class MyHomePage extends ConsumerWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button say Hello World:',
),
Text(
ref.watch(helloProvider).toString(),
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
statement = '${statement}Hello World!';
ref.watch(helloProvider.notifier).state = statement;
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
実行して+ボタンを押すと、「Hello World!」の文字が表示されるよ。
押せば押しただけ狂ったように表示されるよ。
制限つけていないから、表示できなくなったところでエラーになるけどね。
コピペするときは、あらかじめpubspec.yamlにflutter_riverpodを追加しておいてね。
dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^2.1.3 ←これ追加
4.ソースの解説
元のソースから変更したところを説明していくよ。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; ←追加
flutter_riverpodのimportを追加するよ。
final helloProvider = StateProvider<String>((ref) => ' ');
String statement = '';
グローバルでProviderを追加するよ。Hello Worldを出すから、属性はStringにするよ。
ついでに文字を入れておくエリアを定義するよ。カウンタアプリの「_counter」にあたるやつだね。
void main() {
runApp(
const ProviderScope( ←これで囲むよ
child: MyApp(),
),
);
}
メインのところは、ProviderScpoeで囲めって書いてあるから、言われた通り囲ったよ。
VSCodeにconstつけろって怒られたからつけてるけど、正解か?
class MyHomePage extends ConsumerWidget { ←StatefulWidgetから変更
const MyHomePage({Key? key, required this.title}) : super(key: key);
MyHomePageのWidgetを、StatefulWIdgetからConsumerWIdgetに変更する。
これでこの中でProviderが使えるようになるよ。
それから、この下にある「State createState() => _MyHomePageState(); 」以下_MyHomePageStateのclassをまるっと消してしまうよ。
デフォルトのカウントアプリでは_MyHomePageStateでカウントの処理を書いていたけれど、今回の変更でonPressに直接処理を書いているので、ここはいらなくなるよ。
@override
Widget build(BuildContext context, WidgetRef ref) { ←WidgetRef refを追加
return Scaffold(
appBar: AppBar(
title: Text(title), ← ちょっと変えた
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button say Hello World:', ←ちょっと変えた
),
Text(
ref.watch(helloProvider).toString(), ← 表示する値をref.watchで取得
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
statement = '${statement}Hello World!'; ← クリックするたび「Hello World!」をセットするように変更
ref.watch(helloProvider.notifier).state = statement; ← 「Hello World!」が設定されたエリアをProviderにセット
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
いよいよ実際の処理の部分だ。
riverpodに直接関係する部分は、以下の修正をしているよ。
・Widget buildの引数にWidgetRef refを追加したよ。
これでProviderの値をやり取りできるようになるよ。
・ref.watch(helloProvier)で取得した値を画面に表示するようにしたよ。
デフォルトのカウンタアプリでは、カウントする処理を文字列補間でそのまま表示していたけれど、今回はtoStringでhelloProviderの値を表示したよ。
・「Hello World!」の文字を出すようにしたよ。
カウントする代わりに、「Hello World!」を表示するようにしたよ。ただセットするだけだと面白くないから、ボタンを押したら後ろに「Hello World!」を追加するようにしたよ。
5.できた!
これでカウンタアプリにRiverpodを組み込むことができたよ。
ぶっちゃけ見た目が変わるわけでないから、達成感ないよね。
次は画面一式を状態管理してみるよ。てことはよく見るあれを使うってことか?
刮目して待て!次号!