🦿

[Flutter]GetX StateMixin講座

4 min read

StateMixin

どうも,えんでばーです。
僕はGetXのヘビーユーザーなんですが、
そのGetXの中で一番好きなStateMixinを紹介したいと思います。

StateMixinは非同期処理する際のUIの状態を管理してくれる超便利なものです。

例えばこんな感じで作る事ができます(gif)。

demo

待機->Loading->successという流れになっています。
ちなみに上の画像のアプリは僕の個人アプリなので興味ある方は入れて使ってみてください。↓

https://apps.apple.com/us/app/multistream-動画複数視聴アプリ/id1593437968

実装方法

GetXのセットアップは終わっているものとします。

https://pub.dev/packages/get

1. コントローラーの作成

class AddLinkController extends GetxController with StateMixin<String> {}
StateMixin<T> {}

のTにはViwe側に返す型が必要です。

1. onReadyで非同期処理をする

class GetNameController extends GetxController with StateMixin<String> {
  
  void onReady() async {
    super.onReady();
    try {
      change(null, status: RxStatus.loading());
      final String usersName = await getName();
      if (usersName == '') {
        change(usersName, status: RxStatus.empty());
      } else {
        change(usersName, status: RxStatus.success());
      }
    } catch (err) {
      change(null, status: RxStatus.error());
    }
  }
  
  Future<String> getName() async {
    await Future.delayed(Duration(seconds: 2));
    return 'ちんもぎくん';
  }
}

1. View側の制御

class HomePage extends StatelessWidget {
  GetNameController _getNameController = Get.put(GetNameController());
  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: _getNameController.obx(
          (userName) => Text('$userName'),
          onLoading: CircularProgressIndicator(),
          onEmpty: Text('空です'),
          onError: (error) => Text('エラー'),
        ),
      ),
    );
  }
}

_getNameController.obx()で括って状態のハンドリングをします。
こうする事で上記のコードでは、CircularProgressIndicator()が表示され2秒後に名前が表示されます。

1度更新をしたいって場合があれば onReady()を呼び出せばもう1度実行されます。

リアクティブな画面には向きませんが一度だけ表示したい場合なんかに使ってみると便利です。

実践編

これからする流れ

1. ログインしているかどうか?判別
2. あればそのままHomeViewへ
2.  無ければUser作成中画面出して、作成し終わったらHomeViewへ

っていうのを作っていこうと思います。

まずUserがあるかどうか判別

class AuthController extends GetxController with StateMixin<User?> {
  
  void onReady() async {
    super.onReady();
    try {
      change(null, status: RxStatus.loading());//最初はLoding
      final User? currentUser = await existCurrentUser();//User情報取ってくる
      if (currentUser == null) {
        change(null, status: RxStatus.empty());
	//Userがないならログインし作成
        await AuthRepository.signInAnonymously();
	//匿名でログインしています。そのまま書いてもエラーが起きます。
        await SetUpRepository.createUserInfo();
	//ここでFirestoreにUserの初期値を入れています。そのまま書いてもエラーが起きます。
        change(currentUser, status: RxStatus.success());
      } else {
	//あるならそのままstateをsuccessに
        change(currentUser, status: RxStatus.success());
      }
    } catch (err) {
             //error出たらエラー
      change(null, status: RxStatus.error());
    }
  }

  Future<User?> existCurrentUser() async {
    return FirebaseAuth.instance.currentUser;
  }
}

view側

class Home extends StatelessWidget {
  final AuthController authController = Get.put(AuthController());
  
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: whiteColor,
      body: SafeArea(
        child: authController.obx(
	    //User情報があったもしくは作成し終わった場合
          (_) => HomeView(),
          onLoading: const Center(
            child: CircularProgressIndicator(),
          ),
          onEmpty: const Center(
                     //Userが作成中はこの画面
            child: Text(
              "ユーザーデータを作成しています.",
              style: text18bold,
            ),
          ),
          onError: (_) => const Text(
            "Error",
          ),
        ),
      ),
    );
  }
}

はいこんな感じでstatusの管理ができました。

最後に

めっちゃシンプルでとても簡単にできるのでStateMixin使ってみて下さい。
GetX使うなら一番使ってもらいたいやつなんで、ぜひ参考になれば!

おまけ

最初に載せたgifの画像のキラキラがかっこいいと思いますが

https://pub.dev/packages/skeletons
このパッケージを使っています。
このパッケージの解説も書いています。

Discussion

ログインするとコメントできます