关于 GetX State Management Patterns
GetX State Management Patterns 是面向使用 GetX 的 Flutter 开发者的编码技能,涵盖响应式状态、依赖注入、导航和控制器生命周期,并说明如何避免将业务逻辑放入控制器。
主要功能
- 01响应式变量与组件
- 02使用 Bindings 进行依赖注入
- 03路由导航与参数传递
- 04控制器生命周期指引
- 05Snackbar 与对话框
- 06状态管理最佳实践
适用场景
- 01在 Flutter 组件中显示响应式数据
- 02通过 Bindings 注册控制器和服务
- 03在命名路由或直接路由间导航
- 04将业务逻辑放在控制器之外
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ kaakati/ rails-enterprise-dev --skill getx-state-management-patterns安装后在 Claude Code 中输入/getx-state-management-patterns确认已加载。
详细介绍
GetX 状态管理模式
响应式状态管理
响应式变量
class UserController extends GetxController {
// Simple reactive variable
final count = 0.obs;
// Complex reactive variable
final user = Rx<User?>(null);
// Reactive list
final users = <User>[].obs;
// Reactive map
final settings = <String, dynamic>{}.obs;
// Getters (recommended)
int get countValue => count.value;
User? get currentUser => user.value;
}
响应式组件
// Option 1: Obx (lightweight)
Obx(() => Text(controller.count.toString()))
// Option 2: GetX (with dependency injection)
GetX<UserController>(
builder: (controller) => Text(controller.user?.name ?? 'Loading...'),
)
// Option 3: GetBuilder (no reactive variables needed)
GetBuilder<UserController>(
builder: (controller) => Text(controller.userName),
)
依赖注入
注册方法
// Immediate instance
Get.put(UserController());
// Lazy instance (created when first used)
Get.lazyPut(() => UserController());
// Singleton (persists across routes)
Get.putAsync(() => StorageService().init());
// Fenix (recreates when route is accessed again)
Get.lazyPut(() => UserController(), fenix: true);
Bindings 模式
class UserBinding extends Bindings {
@override
void dependencies() {
// Data sources
Get.lazyPut(() => UserProvider(Get.find()));
Get.lazyPut(() => UserLocalSource(Get.find()));
// Repository
Get.lazyPut<UserRepository>(
() => UserRepositoryImpl(Get.find(), Get.find()),
);
// Use cases
Get.lazyPut(() => GetUser(Get.find()));
// Controller
Get.lazyPut(() => UserController(getUserUseCase: Get.find()));
}
}
导航
基本导航
// Navigate to route
Get.to(() => ProfilePage());
// Navigate with name
Get.toNamed('/profile');
// Navigate and remove previous
Get.off(() => LoginPage());
// Navigate and remove all previous
Get.offAll(() => HomePage());
// Go back
Get.back();
// Go back with result
Get.back(result: user);
带参数导航
// Send arguments
Get.toNamed('/profile', arguments: {'id': '123'});
// Receive arguments
final args = Get.arguments as Map<String, dynamic>;
final id = args['id'];
路由配置
class AppRoutes {
static const initial = '/splash';
static final routes = [
GetPage(
name: '/splash',
page: () => SplashPage(),
binding: SplashBinding(),
),
GetPage(
name: '/login',
page: () => LoginPage(),
binding: AuthBinding(),
transition: Transition.fadeIn,
),
GetPage(
name: '/home',
page: () => HomePage(),
binding: HomeBinding(),
middlewares: [AuthMiddleware()],
),
];
}
控制器生命周期
class UserController extends GetxController {
@override
void onInit() {
super.onInit();
// Called immediately after controller is allocated
loadUser();
}
@override
void onReady() {
super.onReady();
// Called after widget is rendered
analytics.logScreenView();
}
@override
void onClose() {
// Clean up resources
_subscription.cancel();
super.onClose();
}
}
Snackbars 和对话框
// Snackbar
Get.snackbar(
'Success',
'User created successfully',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.green,
);
// Dialog
Get.dialog(
AlertDialog(
title: Text('Confirm'),
content: Text('Are you sure?'),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text('Cancel'),
),
TextButton(
onPressed: () {
deleteUser();
Get.back();
},
child: Text('Delete'),
),
],
),
);
// Bottom sheet
Get.bottomSheet(
Container(
child: Column(
children: [
ListTile(
title: Text('Option 1'),
onTap: () => Get.back(result: 1),
),
],
),
),
);
最佳实践
✅ 应当
- 使用 bindings 进行依赖注入
- 使用私有响应式变量,并提供公共 getter
- 在
onClose()中清理资源 - 使用有意义的控制器名称(例如,
UserController,而不是Controller1) - 将业务逻辑放在用例中,而不是控制器中
❌ 不应
- 不要直接在组件中创建控制器
- 不要将业务逻辑放在控制器中
- 不要忘记释放流和订阅
- 不要过度使用全局状态
- 不要创建循环依赖
应避免的反模式
// ❌ BAD: Business logic in controller
class UserController extends GetxController {
Future<void> createUser(String name, String email) async {
// Direct API call in controller
final response = await http.post(...);
// Business logic in controller
if (response.statusCode == 201) {
user.value = User.fromJson(response.body);
}
}
}
// ✅ GOOD: Delegate to use case
class UserController extends GetxController {
final CreateUser createUserUseCase;
Future<void> createUser(String name, String email) async {
final result = await createUserUseCase(name, email);
result.fold(
(failure) => _handleError(failure),
(user) => user.value = user,
);
}
}
评论
支持 Markdown