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
使用,用于从页面根部提供logicTag
ConsumerMixin
: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
👍 ,并多多支持!
好了,以上介绍的是针对新页面的使用姿势,对于已有页面要如何使用,请等待下一篇~
