Flutter必学的Getx状态管理库
什么是 GetX?
一个简单、高效、强大的管理状态、路由管理库
学习目标
- 掌握使用
GetX
管理状态 - 了解基础
GetX
状态管理的原理
GetX状态管理的优势
- 精确渲染,只会渲染依赖状态变化的组件而不会全部组件渲染一遍
- 安全性高,当程序出现错误时,不会因为重复更改状态导致崩溃
- 有个
GetX
永远不需要声明状态组件, 忘记StatefulWidget
组件 - 实现
MVC
架构,将业务逻辑写到控制器中,视图层专注于渲染 - 内置了防抖/节流、首次执行等功能
- 自动销毁控制器,无需用户手动销毁
用法
1.1声明响应式状态
有三种声明方式,使用哪一种都可以 推荐第三种
1.1.1 使用声明,结合Rx{Type}
final name = RxString(''); // 每种内置的类型都有对应的类
final isLogged = RxBool(false);
final count = RxInt(0);
final balance = RxDouble(0.0);
final items = RxList<String>([]);
final myMap = RxMap<String, int>({});
1.1.2 泛型声明 Rx
final name = Rx<String>('');
final isLogged = Rx<Bool>(false);
final count = Rx<Int>(0);
final balance = Rx<Double>(0.0);
final number = Rx<Num>(0);
final items = Rx<List<String>>([]);
final myMap = Rx<Map<String, int>>({});
// 自定义类 声明方法
final user = Rx<User>();
1.1.3以.obs
作为值(推荐使用)
final name = ''.obs;
final isLogged = false.obs;
final count = 0.obs;
final balance = 0.0.obs;
final number = 0.obs;
final items = <String>[].obs;
final myMap = <String, int>{}.obs;
// 自定义类 声明方法
final user = User().obs;
2.1 使用响应状态到视图中
有两种方法使用状态:
- 基于
Obx
收集依赖状态 - 基于
GetX<Controller>
获取对应的控制器类型
2.1.1基于Obx收集依赖状态
十分简单,我们只需要使用静态类即可达到动态更新效果。
- 创建一个 Controller
// HomeController 可以写到一个专门管理控制器的文件中,这样方便维护
// 就像 React 需要把 Hook 单独提取一个文件一样
class HomeController extends GetxController {
var count = 0.obs;
increment() => count++;
}
- 导入创建的 Controller 并使用它
class Home extends StatelessWidget {
const Home({super.key});
@override
Widget build(BuildContext context) {
// 寻找Controller
HomeController c = Get.find<HomeController>();
return Obx(
() => Scaffold(
body: ElevatedButton(
// 通过`c.count.value`使用状态,也可以不使用.value,.value可选的
child: const Text("${c.count}"),
onPressed: () => c.count++, // 改变状态,
),
),
);
}
}
2.1.2 基于GetX<Controller>
获取对应的控制器类型
这种做法需要三个步骤
- 声明一个控制器
// HomeController 可以写到一个专门管理控制器的文件中,这样方便维护
class HomeController extends GetxController {
var count = 0.obs;
increment() => count++;
}
- 在
GetMaterialApp
类中初始化时导入对应的控制器
// main.dart
void main() {
runApp(GetMaterialApp(
// 如果不写这一步那么GetX将无法找到HomeController控制器
initialBinding: InitBinding(),
home: const Home(),
));
}
class InitBinding implements Bindings {
@override
void dependencies() {
Get.put(HomeController());
}
}
- 在对应组件或页面中使用
GetX<Controller>
实现数据的响应
class Home extends StatelessWidget {
const Home({super.key});
@override
Widget build(BuildContext context) {
// 这样就可以正常使用了
return Obx<HomeController>(
builder: (c) => Scaffold(
body: ElevatedButton(
child: const Text(c.count.value),
onPressed: () => c.count++,
),
),
);
}
}
3.1 监听状态更新的工具函数
- 当依赖的值发生变化后会触发回调函数
var count = 0.obs;
// 每当 count 发生改变的时候就会触发回调函数执行
ever(count, (newCount) => print("这是count的值: $newCount"));
// 只有首次更新时才会触发
once(count, (newCount) => print("这是count的值: $newCount"));
/// 类似于防抖功能频繁触发不会每次更新,只会停止更新count后的 1秒才执行(这里设置成了1秒)
debounce(count, (newCount) => print("这是count的值: $newCount"), time: Duration(seconds: 1));
/// 类似于节流功能 频繁更新值每秒钟只触发一次 (因为这里设置成了1秒)
interval(count, (newCount) => print("这是count的值: $newCount"), time: Duration(seconds: 1));
GetX状态管理的疑惑
1.1 哪些地方可以使用.obs
?
- 可以直接在类中赋值使用
class RxUser {
final name = "Camila".obs;
final age = 18.obs;
}
- 直接将整个类都变成可观察对象
class User {
User({String name, int age});
var name;
var age;
}
final user = User(name: "Camila", age: 18).obs;
1.1.2 一定要使用xxx.value
获取值吗?
这个并没有强制要求使用xxx.value
获取值,可以直接使用xxx
这能让代码看起来更加简洁
1.2 可观察对象是类如何更新?
- 两种方式可以更新,使用其中一种即可
class User() {
User({this.name = '', this.age = 0});
String name;
int age;
}
final user = User().obs;
// 第一种方式
user.update( (user) {
user.name = 'Jonny';
user.age = 18;
});
// 第二种方式
user(User(name: 'João', age: 35));
// 使用方式
Obx(()=> Text("名字 ${user.value.name}: 年龄: ${user.value.age}"))
// 可以不需要带.value访问,需要将user执行
user().name;
GetX状态管理的一些原理
1.1.1.obs
原理是什么?
var name = "dart".obs
- 源码只是通过
StringExtension
向String
中扩展了一个get
属性访问器 - 原理还是通过
RxString
做绑定
tips: 如果想查看源码的话可以通过 control
键 + 左击.obs
就可以进入源码里面了
1.2 Obx
的基本原理是什么?
- 简而言之,Obx其实帮我们包裹了一层有状态组件
var build = () => Text(name.value)
Obx(build);
继承了一个抽象ObxWidget
类,将传递进来的build
方法给了ObxWidget
,还得看看ObxWidget
做了什么
ObxWidget
继承了有状态组件,并且build
函数让Obx
类实现了
_ObxWidget
主要做了两件事情
- 初始化的时候监听依赖收集,销毁时清空依赖并关闭监听。这是
Obx
的核心 - 将
Obx
实现的build
函数传递给了RxInterface.notifyChildren
执行
NotifyManager
是一个混入,主要功能
- subject属性用于传递更新通知
_subscriptions
属性用于存储RxNotifier
实例的订阅列表canUpdate
方法检查是否有任何订阅者addListener
用于将订阅者添加到订阅列表中,当 RxNotifier 实例的值发生变化时,它将通过 subject 发出通知,并通知所有订阅者listen
方法监听subject
变化并在变化时执行回调函数close
关闭所有订阅和释放内存等
作者:liang的编程之路
链接:https://juejin.cn/post/7222656390547914809
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://juejin.cn/post/7222656390547914809
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。