likes
comments
collection
share

一、Flutter必学的Getx状态管理库

作者站长头像
站长
· 阅读数 14

什么是 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

一、Flutter必学的Getx状态管理库

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

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

1.2 Obx的基本原理是什么?

  • 简而言之,Obx其实帮我们包裹了一层有状态组件
var build = () => Text(name.value)

Obx(build);

一、Flutter必学的Getx状态管理库

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

一、Flutter必学的Getx状态管理库

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

一、Flutter必学的Getx状态管理库

_ObxWidget主要做了两件事情

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

一、Flutter必学的Getx状态管理库

NotifyManager是一个混入,主要功能

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