🌏
【Flutter】関数型リアクティブプログラミングパッケージ「asp」について
はじめに
パッケージとして展開されたのが1ヶ月前と、かなり新しいパッケージとなりますが
今後のバージョンアップに期待の意味も込めて、触ってみたいと思います。
概要
導入
こちらの公式からプロジェクトに取り込みましょう
準備
-
InheritedWidget
を継承しているRxRoot
をrunApp
の親として定義しましょう
runApp(const RxRoot(child: MyApp()));
関数
-
select
関数を使用して監視対象のAtom
オブジェクトを指定します。
final counter = Atom<int>(0);
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
final value = context.select(() => counter.value);
...
...
}
}
※また、複数のAtomをselectすることも可能です。
final counter = Atom<int>(0);
final counter2 = Atom<int>(0);
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
final value = context.select(() => [counter, counter2]);
...
...
}
}
-
select
関数以外に、明示的に監視対象の値を加工して提供したい場合に、getterを使用して監視することが可能
final counter = Atom<int>(0);
String get counterText => 'カウント数 - ${counter.value}';
Widget
RxBuilder
- スコープを絞った状態管理
RxBuilder(
builder: (_) => Text('${counter.value}'),
)
RxCallback
-
callback
関数と同様、対象のAtomオブジェクトに変化が生じた際に、rxObserver
が変化を受け取り、effect
関数にコールバックとしてイベントを送信する
RxCallback(
effects: [
rxObserver(
() => counter.value,
effect: (value) => print(value),
),
],
child: const Text(''),
)
コレクション
RxList
- 値の追加や削除などのリアクティブオブジェクトとして拡張したList
final rxList = RxList<String>([]);
class RxListWidget extends StatelessWidget {
const RxListWidget({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Column(
children: [
...List.generate(
rxList.length,
(index) => Text(rxList[index]),
),
ElevatedButton(
onPressed: () => rxList.add('${counter.value}'),
child: const Text('Tap')),
],
);
}
}
非同期
RxFuture
- status / error / resultの結果を監視できる非同期リアクティブラッパー
final rxFuture = getCounterFuture(100).asAtom();
Future<int> getCounterFuture(int value) async {
await Future.delayed(const Duration(milliseconds: 500));
return value;
}
...
...
rxObserver(() {
if (rxFuture.status == FutureStatus.pending) {
return;
}
number = rxFuture.data ?? 0;
print('$number');
});
実装
Value Notifier
notifier.dart
final counterNotifier = Atom<CounterNotifier>(CounterNotifier());
class CounterNotifier extends ValueNotifier<int> {
CounterNotifier() : super(0);
void increment(int count) {
value = count;
}
void decrement(int count) {
value = count;
}
}
UI
main.dart
void main() {
runApp(const RxRoot(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
// notifierを監視
final notifier = context.select(() => counterNotifier.value);
return MaterialApp(
home: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('${notifier.value}'),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
// 値を+1に更新
onPressed: () => notifier.increment(notifier.value + 1),
child: const Text('increment'),
),
const SizedBox(width: 8),
ElevatedButton(
// 値を-1に更新
onPressed: () => notifier.decrement(notifier.value - 1),
child: const Text('decrement'),
),
],
)
],
),
),
);
}
}
まとめ
今回は基本的な部分を記載してみました。
サンプルコードなどを拝見すると、応用を効かせたコーディングや
Reducer
を用いたAtomsパターンなど興味深い内容が詳細に記載されています。
Flutter自体、様々な状態管理手法が提供されていますが、この「asp」も今後、その中の一つとして存在していく可能性もありますので、ご興味のある方は手元でぜひご確認いただけたらと思います。
参考
Discussion