※こちらの記事は【Flutter】色んな状態管理手法でカウンターアプリを作ってみるの一部として作成された記事です
勢い旺盛なニューカマー GetX
今回は賛否ありつつもProviderに勝る人気のフレームワークGetX
の状態管理を使ってカウンターアプリを作っていきます
使用するPackage:
- get v4.3.8
概要
-
GetX
自体は状態管理手法というよりFlutterのフレームワーク - 状態管理、ルーティング、依存関係の注入に対する機能を提供
- Jonny Borges氏が開発
- GithubのLIKE数では既にProviderを超える人気
- しかし作者が以前に自身のライブラリのパフォーマンスを誇張したり、他のライブラリに対して否定的なコメントを繰り返した為、一部のFlutter開発者からは嫌われている等論争の的になっているライブラリの様です
- 初版リリースは2019年11月
全体像
- 前述の通り、
GetX
自体はFlutter用のフレームワーク - その中の状態管理と依存関係の注入機能を今回は使います
特徴としては、
- contextを使わず、どこからでも状態管理クラスにアクセス可能
- 状態変数自体をリアクティブなクラスでラップする
実際に例で見た方が早いかもしれません。
キーとなるクラスやメソッド
-
GetxController
クラス:状態管理クラスが継承するクラス -
Rx<T>
クラス:状態変数をラップし、監視可能なリアクティブなオブジェクトにする -
.obs
:オブジェクトをRxオブジェクトでラップし、インスタンス化する -
Get.put(<GetxController>)
メソッド:依存関係を注入するメソッド -
Get.find()
メソッド:注入されたGetxControllerへアクセスするメソッド -
Obx
クラス:状態変数の変化に反応し、ラップしたwidgetを再描画します
準備
カウンターアプリを例に実際見ていきましょう。
サンプルコードはこちら
1. Stateクラス
- 今回はCountフィールドを持つ
CounterObj
クラスを定義。 -
RxInt
はint
型の状態変数を持つRx
オブジェクトです。 -
0.obs
とする事で0を状態変数に持つRx
オブジェクトをインスタンス化しています。
class CounterObj {
CounterObj() : count = 0.obs;
RxInt count;
}
2. 状態管理クラス(GetXController)
-
GetXController
クラスを継承する状態管理クラスを定義します。 - 状態変数として管理するのは先程定義した
CounterObj
クラスです。 - その為、
CounterObj
もCouterObj.obs
とする事で監視可能なRx
オブジェクトとしてインスタンス化します。
class GetXCounterController extends GetxController {
Rx<CounterObj> _counter = CounterObj().obs;
Rx<CounterObj> get counter => _counter;
void incrementCounter() => _counter.value.count++;
void decrementCounter() => _counter.value.count--;
void resetCounter() => _counter.value.count.value = 0;
}
- 状態変数の変更ではRxインスタンスのvalueプロパティに状態変数が格納されているので、それを直接操作します。
3. 依存関係の注入
- 依存関係の注入には
Get.put
メソッドを使います。 - 以下のように
Get.put(<GetXController>)
メソッドを実行する事でそのwidgetツリー以下のwidgetでGet.find
メソッドで引数に渡したGetXControllerにアクセスする事が出来ます。
@override
Widget build(BuildContext context) {
Get.put(GetXCounterController());
return const _GetXCounterPage();
}
状態へのアクセス
- 状態管理クラスへのアクセスは
Get.find
メソッドを使います
final GetXCounterController c = Get.find();
...
FloatingActionButton(
onPressed: c.incrementCounter,
tooltip: 'Increment',
heroTag: 'Increment',
child: Icon(Icons.add),
),
...
状態変数の変更に伴った再描画
-
Obx
クラスでラップする事で、状態変数に変更があった際に再描画させる事ができます。
Obx(
() => Text(
'${c.counter.value.count}',
style: Theme.of(context).textTheme.headline4,
),
),
全体
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:state_management_examples/widgets/main_appbar.dart';
// 状態クラス
class CounterObj {
CounterObj() : count = 0.obs;
RxInt count;
}
// 状態管理クラス
class GetXCounterController extends GetxController {
Rx<CounterObj> _counter = CounterObj().obs;
Rx<CounterObj> get counter => _counter;
void incrementCounter() => _counter.value.count++;
void decrementCounter() => _counter.value.count--;
void resetCounter() => _counter.value.count.value = 0;
}
// 依存関係を注入
class GetXCounterPage extends StatelessWidget {
const GetXCounterPage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
Get.put(GetXCounterController());
return const _GetXCounterPage();
}
}
// カウンター本体
class _GetXCounterPage extends StatelessWidget {
const _GetXCounterPage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
print('rebuild!');
final GetXCounterController c = Get.find();
return Scaffold(
appBar: MainAppBar(
title: 'GetX',
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Obx(
() => Text(
'${c.counter.value.count}',
style: Theme.of(context).textTheme.headline4,
),
),
],
),
),
floatingActionButton: FittedBox(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FloatingActionButton(
onPressed: c.incrementCounter,
tooltip: 'Increment',
heroTag: 'Increment',
child: Icon(Icons.add),
),
const SizedBox(width: 16),
FloatingActionButton(
onPressed: c.decrementCounter,
tooltip: 'Decrement',
heroTag: 'Decrement',
child: Icon(Icons.remove),
),
const SizedBox(width: 16),
FloatingActionButton.extended(
onPressed: c.resetCounter,
tooltip: 'Reset',
heroTag: 'Reset',
label: Text('RESET'),
),
],
),
),
);
}
}
以上でした
どうでしょうか、GetXには他にも様々な機能があり、だいぶ端折った部分もありますが、非常に直感的で学習コストが低いと感じます。
大規模なプロジェクトで状態管理が複雑になる場合に適正かは分かりませんが、個人開発レベルであまり複雑な状態管理が発生しないプロジェクトであれば、非常に強力なツールになると感じます。
他にも多くの機能があるので別途GetXだけを記事にしたいと思います。