こんにちは。
今日は初期アプリの状態管理をriverpodに置き換え、
その使い方やメリットを理解しようと思います。
前回は初期アプリをproviderに置き換えました。
その記事はこちら
また初期アプリの解説記事はこちらになります!
今回もpackageの導入から始めます。
$ flutter pub add flutter_riverpod
そしてmain.dartファイル内で下記インポートと
counterProviderの定義を行います。
import 'package:flutter_riverpod/flutter_riverpod.dart';
final counterProvider = StateProvider((ref) => 0);
ここでStateProviderというクラスが出てきました。
これはriverpod特有のクラスで、こちらを使い状態管理を行います。
StateProvider((ref) => 0);
こう書くことでStateProviderのコンストラクタを呼び出し、
引数として無名関数(refを引数として渡し、0を返す)を渡しています。
そしてこのrefはStateProviderのコンテキスト(ProviderReference)にアクセスするためのものです。
要するにこれまでの文脈を渡し、初期値として0を返しています。
そして、ProviderScopeでアプリ全体をラップします。
これはriverpodを使うための儀式で、こうすることで全てのproviderへグローバルにアクセスできるようになります。
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
最後にMyHomePageをConsumerWidgetを継承する形で書き換えます。
class MyHomePage extends ConsumerWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider);
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
まず、ConsumerWidgetとはなんぞやという話からですが、
こちらもriverpodから提供されるWidgetクラスです。
ConsumerWidgetはproviderから提供される状態をサブスクライブ(購読)し、状態が変更された時に自動的に再構築され、UIが更新されます。
final counter = ref.watch(counterProvider);
またConsumerWidgetはbuildメソッドの際、WidgetRefオブジェクトをパラメータとして受け取り、このWidgetRefを使用して、providerから状態を読み取ります。
そしてcounter変数を用いて、body内で値を表示し、
onPressedイベントが発火した際には
ref.read(counterProvider.notufier)によって、現在の値を1度だけ取得し、
.state++にて1加算しています。
以上がriverpodを使用した状態管理への移行方法になります。
ここまで
StatefulWidgetとsetState
provider
riverpodと試してきましたが、
やはり最近よく使われているだけあって、riverpodが書くソース量も少なく、使いやすそうだなという印象です。ただグローバルに状態にアクセスできることはメリットの反面、非常に多くの箇所からアクセスされるようになると、結合度が高くなるようなデメリットも少なからずあると感じました。
実際に使っていく中で設計など意識していきたいと思いました。