providerと状態管理のriverpod
状態管理
アプリの開発では、サーバーと通信して、結果によって、ステータス変えるのはよくあるものでした。
素の状態管理を実現するにはSRPのルールに従って、InheritedWidgetで、下記の階層(ツリー)を作りました。
問題点
- サンプルは簡単ですが、コードの複雑性はちょっと高いですね。
- 管理対象は増えると、管理はしつらくなります。
- ツリーの階層は深くなる場合、色なトラプル発生しやすいです。
- InheritedWidgetと紐付いているので、MVVCとかのアーキテクチャーの基盤は作れない。
改善目標
上記問題によって、改善の目標は明確になれました。
- 分かりやすいコードがいい。
- 複数状態管理対象は絡まないようにしたい。
- ツリーの階層深い場合でも簡単に対応できます。
- 役割を分離できて、MVVCとかのアーキテクチャー基盤に向いている。
ライブラリー選定
状態管理に関して、ライブラリーはたくさんありますが、自分はよく使うライブラリーをピックアップして、進もうと思います。
provider
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(
MaterialApp(
home: ChangeNotifierProvider(
create: (context) => DemoNetwork(),
child: const Display(),
),
),
);
class DemoNetwork extends ChangeNotifier {
String _result = '通信開始。。。';
DemoNetwork() {
Future.delayed(
const Duration(seconds: 3),
() {
_result = '通信完了しました';
notifyListeners();
},
);
}
String get result => _result;
}
class Display extends StatelessWidget {
const Display({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Consumer<DemoNetwork>(
builder: (context, network, child) => Text(
network.result,
style: Theme.of(context).textTheme.headline5,
),
),
),
);
}
}
解決したもの:
- コードがわかりやすくなりました。
- providerが提供しているクラスで状態管理の対象を管理できます。
- MVVCみたいな基盤は簡単に構築できます。
- providerはデータインジェクターみたいになり、何階層のツリーの呪いから解放できている。
ですが、長い時間でprovider使っていて、デメリットはいくつあるではないかと、ちょっと自分なりにまとめてみました。
- Widgetから解放していないようです、BLoC(「Business Logic Component」)みたいな実装はやり難いかも。
- 実際に使うとき、パラメーターは見つからなく、エラーになったことがよくありました。
- 複数のProviderやConsumerは提供していなく、実装者によって管理は違います。
- 複数のProviderやConsumerの効き範囲によって、お互いに喧嘩したことがある。
riverpod
riverpodシリーズを使って、課題に向けて解決します。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() => runApp(
const MaterialApp(
home: ProviderScope(
child: Display(),
),
),
);
final networkProvider = StateNotifierProvider<NetworkService, String>(
(ref) => NetworkService(),
);
class NetworkService extends StateNotifier<String> {
NetworkService() : super('通信開始。。。');
void updateResult() {
Future.delayed(
const Duration(seconds: 3),
() {
state = '通信完了しました';
},
);
}
}
class Display extends ConsumerWidget {
const Display({Key? key}) : super(key: key);
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: Center(
child: Consumer(
builder: (context, ref, _) {
final service = ref.read(networkProvider.notifier);
service.updateResult();
return Text(
ref.watch(networkProvider),
style: Theme.of(context).textTheme.headline5,
);
},
),
),
);
}
}
providerのChangeNotifier使い方から、StateNotifierになり、Providerのクラスは豊富になり、Service層も分離できるようになりました。
真の状態管理に達したと思います。
上記のコード表したように、要望のリストクリアできたかなぁと思います。
- 最高にわかりやすいコードではないかと思います。
- UIの部分と分けることができて、アーキテクチャーの構造はますます作りやすくなりました。
- 複数のProviderは分離できて、ライフサイクルはriverpodによってコントロールできて、安心感あります。
最後
いかがでしたか、
結論として、riverpodシリーズは、状態管理を完璧に行うことができるだろう。
providerといい、riverpodといい、開発者は同じ人でわかるでしょうか。
なぜ両方を運営し続いているだろうと、自分的の認識では、
providerの立場はriverpodみたいな状態管理ライブラリーの競争者ではなく、ツールです。
例えば、flutter特有のインジェクター的なものはproviderライブラリーはできます。
providerライブラリーは同じプロジェクトの中で他の状態管理ライブラリーと共存できるです、また、使えるパターンは状態管理だけとは限らないです。
アプリ開発基盤を構築する際に、自分にとっては
ProviderとRiverpodは、不可欠なライブラリになっているではないかと思います。
Discussion