Flutter - GetX Helper 助你规范应用 tag
# 一、前言
项目从一开始就选择了 GetX 做为我们的状态管理方案,但是 GetX 对 Logic 的理想使用是一个类型仅存在一个实例的方式,而同一类型不同物件的详情页,则需要我们通过 tag 的方式去解决。
在这种情况下,在各个子 Widget 中想要去获取相应的 logic,就需要到处写相同的 tag 或者直接传 logic 实例,十分恶心。
我见过解决这个问题的一个方案,核心逻辑是以 Map + List 的方式去存储 tag,通过 Logic 类型从 Map 获取 List,再直接获取 List 的最后一个数据,删除也是直接操作最后一个,但是这样是不可靠的。
比如打开并替换当前页这个场景,新页面会添加 tag 到 List 中,被替换的页面会将这个 tag 移除,而在此时被替换页面的 logic 被移除,但是其对应的 tag 还在,且为 List 里的最后一个,然后新页面拿着这个旧的 tag 去获取 logic,就会出现 XXXController" not found. You need to call "Get.put(XXXController())" or "Get.lazyPut(()=>XXXController())" 的错误~
当然不同的小伙伴对 GetX 的使用有着不同的理解,也会导致各种各样的问题,如果你有遇到其它的使用场景问题,欢迎留言分享。
我自己也实现了一套方案,以页面为维度,安全且方便地获取其 logic 和 logicTag,并且规范使用方式。
https://github.com/LinXunFeng/getx_helper (opens new window)
# 二、集成
打开 https://pub.dev/packages/getx_helper (opens new window) ,复制最新版本。
将 getx_helper 添加到你的 pubspec.yaml 中,并执行 flutter pub get
dependencies:
getx_helper: latest_version
在需要使用的地方中导入 getx_helper
import 'package:getx_helper/getx_helper.dart';
# 三、插件
# 1、安装
打开 vscode 的扩展,搜索 GetX Helper 并安装

安装完成后,在 Flutter 项目下,目录右击的菜单中会多如下选项

# 2、使用
这里假设你会将所有的页面都存放在 feature 目录,结构如下
.
├── main.dart
└── feature
右击 feature 目录,在菜单中选择 GetX: Simple Page,输入 home 回车,即可快速创建一个简单页面
.
├── main.dart
└── feature
└── home
├── header
│ └── home_header.dart
├── logic
│ └── home_logic.dart
├── page
│ └── home_page.dart
└── state
└── home_state.dart
如果你想拆分 Widget,可按如下步骤:
- 先去到
home目录自行创建一个widget目录 - 然后右击该
widget目录,选择GetX: Mixin Widget - 输入
Widget名,如home_body_view,回车
这样即可快速生成一个模板 Widget,你可以在该模板 Widget 里直接拿到 logic 和 logicTag。
# 四、结构说明
此时的目录结构如下
.
├── main.dart
└── feature
└── home
├── header
│ └── home_header.dart
├── logic
│ └── home_logic.dart
├── page
│ └── home_page.dart
├── state
│ └── home_state.dart
└── widget
└── home_body_view.dart
结构的分层说明如下
| 文件 | 作用 |
|---|---|
header | 声明类型,定义枚举、视图刷新 ID,存放业务所需的常量数据等 |
logic | 处理业务逻辑 |
page | 页面结构,可直接拿到 logic 和 logicTag |
state | 数据存储,可通过 logic.state 进行访问 |
widget | 拆分的子部件,可直接拿到 logic 和 logicTag |
# 五、代码简介
# header
在 header 文件中定义了两个 Mixin
typedef HomeLogicPutMixin<W extends StatefulWidget>
= GetxLogicPutStateMixin<HomeLogic, W>;
typedef HomeLogicConsumerMixin<W extends StatefulWidget>
= GetxLogicConsumerStateMixin<HomeLogic, W>;
PutMixin:page使用,用于从页面根部提供logicTagConsumerMixin:widget使用,用于获取logicTag和logic
# page
class HomePage extends StatefulWidget {
const HomePage({super.key});
State<HomePage> createState() => HomePageState();
}
class HomePageState extends State<HomePage> with HomeLogicPutMixin<HomePage> {
HomeLogic initLogic() => HomeLogic();
// @override
// String? customLogicTag() {
// return "https://github.com/LinXunFeng/getx_helper";
// }
Widget buildBody(BuildContext context) {
// with 了 PutMixin 后,可直接获取到 logic 和 logicTag
// lxf -- Instance of 'HomeLogic' -- 20651749399422401 -- Instance of 'HomeState'
print('lxf -- $logic -- $logicTag -- ${logic.state}');
return GetBuilder<HomeLogic>(
tag: logicTag,
builder: (_) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
centerTitle: true,
),
body: const HomeBodyView(),
);
},
);
}
}
# 步骤
PutMixin用于页面的State进行with- 重写
initLogic方法返回logic实例 - 重写
buildBody方法,该方法充当以前的build方法 - 如果你想自定义
logicTag的值,可以重写customLogicTag方法
在 with 了 PutMixin 后,可直接获取 logic 和 logicTag。
# initState
需要注意的是,如果你是在 initState 方法中去使用 logic 和 logicTag,则请先执行 super.initState(),如:
void initState() {
super.initState();
debugPrint('logic -- $logic');
debugPrint('state -- ${logic.state}');
debugPrint('tag -- $logicTag');
}
# keepAlive
如果你 with 了 PutMixin,那 with AutomaticKeepAliveClientMixin 就不再适用,需要调整为使用 KeepAliveWidget 去包裹。
class HomePageState extends State<HomePage> with HomeLogicPutMixin<HomePage> {
...
Widget buildBody(BuildContext context) {
Widget resultWidget = GetBuilder<HomeLogic>(
tag: logicTag,
...
);
resultWidget = KeepAliveWidget(
child: resultWidget,
);
return resultWidget;
}
}
import 'package:flutter/material.dart';
class KeepAliveWidget extends StatefulWidget {
const KeepAliveWidget({
super.key,
required this.child,
});
final Widget child;
State<KeepAliveWidget> createState() => _KeepAliveWidgetState();
}
class _KeepAliveWidgetState extends State<KeepAliveWidget>
with AutomaticKeepAliveClientMixin {
bool get wantKeepAlive => true;
Widget build(BuildContext context) {
super.build(context);
return widget.child;
}
}
# widget
class HomeBodyView extends StatefulWidget {
const HomeBodyView({super.key});
State<HomeBodyView> createState() => _HomeBodyViewState();
}
class _HomeBodyViewState extends State<HomeBodyView>
with HomeLogicConsumerMixin<HomeBodyView> {
Widget build(BuildContext context) {
// with 了 ConsumerMixin 后,可直接获取到 logic 和 logicTag
// lxf -- Instance of 'HomeLogic' -- 20651749399422401 -- Instance of 'HomeState'
print('lxf -- $logic -- $logicTag -- ${logic.state}');
return const Center(
child: Text('Home body'),
);
}
}
ConsumerMixin 用于 Widget 的 State 进行 with,在 with 了 ConsumerMixin 后,也可直接获取 logic 和 logicTag。
跟 PutMixin 一致,如果你是在 initState 方法中去使用,则请先执行 super.initState()。
# 六、最后
手敲这些文件和代码确实会很复杂,但有了相应的插件,这些都变得极为简单,不仅统一了使用规范,还提高了工作效率。
开源不易,如果你也觉得这个库好用 (https://github.com/LinXunFeng/getx_helper (opens new window)),请不吝给个 Star 👍 ,并多多支持!
好了,以上介绍的是针对新页面的使用姿势,对于已有页面要如何使用,请等待下一篇~

- 01
- Flutter 多仓库本地 Monorepo 方案与体验优化10-25
- 02
- Flutter webview 崩溃率上升怎么办?我的分析与解决方案10-19
- 03
- Flutter - Melos Pub workspaces 实践10-12