注册

Flutter必学的Getx状态管理库

什么是 GetX?


一个简单、高效、强大的管理状态、路由管理库


学习目标



  • 掌握使用GetX管理状态
  • 了解基础GetX状态管理的原理

GetX状态管理的优势



  1. 精确渲染,只会渲染依赖状态变化的组件而不会全部组件渲染一遍
  2. 安全性高,当程序出现错误时,不会因为重复更改状态导致崩溃
  3. 有个GetX永远不需要声明状态组件, 忘记StatefulWidget组件
  4. 实现MVC架构,将业务逻辑写到控制器中,视图层专注于渲染
  5. 内置了防抖/节流、首次执行等功能
  6. 自动销毁控制器,无需用户手动销毁

用法


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 使用响应状态到视图中


有两种方法使用状态:



  1. 基于Obx收集依赖状态
  2. 基于GetX<Controller>获取对应的控制器类型

2.1.1基于Obx收集依赖状态


十分简单,我们只需要使用静态类即可达到动态更新效果。



  1. 创建一个 Controller

// HomeController 可以写到一个专门管理控制器的文件中,这样方便维护
// 就像 React 需要把 Hook 单独提取一个文件一样
class HomeController extends GetxController {
var count = 0.obs;
increment() => count++;
}


  1. 导入创建的 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>获取对应的控制器类型


这种做法需要三个步骤



  1. 声明一个控制器

// HomeController 可以写到一个专门管理控制器的文件中,这样方便维护
class HomeController extends GetxController {
var count = 0.obs;
increment() => count++;
}


  1. GetMaterialApp类中初始化时导入对应的控制器

// main.dart
void main() {
runApp(GetMaterialApp(
// 如果不写这一步那么GetX将无法找到HomeController控制器
initialBinding: InitBinding(),
home: const Home(),
));
}
class InitBinding implements Bindings {
@override
void dependencies() {
Get.put(HomeController());
}
}


  1. 在对应组件或页面中使用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



  • 源码只是通过StringExtensionString扩展了一个get属性访问器
  • 原理还是通过RxString做绑定

tips: 如果想查看源码的话可以通过 control键 + 左击.obs就可以进入源码里面了


1.2 Obx的基本原理是什么?



  • 简而言之,Obx其实帮我们包裹了一层有状态组件

var build = () => Text(name.value)

Obx(build);


继承了一个抽象ObxWidget类,将传递进来的build方法给了ObxWidget,还得看看ObxWidget做了什么



ObxWidget继承了有状态组件,并且build函数让Obx类实现了



_ObxWidget主要做了两件事情



  1. 初始化的时候监听依赖收集,销毁时清空依赖并关闭监听。这是Obx的核心
  2. Obx实现的build函数传递给了RxInterface.notifyChildren执行


NotifyManager是一个混入,主要功能



  • subject属性用于传递更新通知
  • _subscriptions属性用于存储RxNotifier实例的订阅列表
  • canUpdate方法检查是否有任何订阅者
  • addListener用于将订阅者添加到订阅列表中,当 RxNotifier 实例的值发生变化时,它将通过 subject 发出通知,并通知所有订阅者
  • listen方法监听subject变化并在变化时执行回调函数
  • close关闭所有订阅和释放内存等

作者:liang的编程之路
链接:https://juejin.cn/post/7222656390547914809
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册