Flutter响应式编程插件reactives的使用
Flutter响应式编程插件reactives的使用
reactives
是一种新的方式,用于在 Flutter 中重用和组合常见的逻辑。你可以将它们视为 React 的 Hook,但适用于 Flutter。
动机
你是否曾经写过类似这样的代码?
class AwesomeWidget extends StatefulWidget {
const AwesomeWidget({Key? key}) : super(key: key);
[@override](/user/override)
_AwesomeWidgetState createState() => _AwesomeWidgetState();
}
class _AwesomeWidgetState extends State<AwesomeWidget> with TickerProviderStateMixin {
late final TextEditingController emailCtrl;
late final TextEditingController passwordCtrl;
late final AnimationController entryAnimation;
late final AnimationController highLightAnimation;
[@override](/user/override)
void initState() {
super.initState();
emailCtrl = TextEditingController();
passwordCtrl = TextEditingController();
entryAnimation = AnimationController(vsync: this);
highLightAnimation = AnimationController(vsync: this);
}
[@override](/user/override)
void dispose() {
emailCtrl.dispose();
entryAnimation.dispose();
highLightAnimation.dispose();
passwordCtrl.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Container();
}
}
这段代码存在几个问题:
- 大部分对象管理逻辑是通用的,可以被重用。
- 容易忘记调用
dispose
方法(坦白地说)。 - 将逻辑耦合到小部件中,使得测试变得困难。
使用 reactives
可以将这段代码转换为:
class AwesomeReactiveWidget extends StatefulWidget {
const AwesomeReactiveWidget({Key? key}) : super(key: key);
[@override](/user/override)
_AwesomeReactiveWidgetState createState() => _AwesomeReactiveWidgetState();
}
class _AwesomeReactiveWidgetState extends State<AwesomeReactiveWidget> with ReactiveHostMixin {
late final emailCtrl = ReactiveTextEditingController(this);
late final passwordCtrl = ReactiveTextEditingController(this);
late final entryAnimation = ReactiveAnimationController(this);
late final exitAnimation = ReactiveAnimationController(this);
[@override](/user/override)
Widget build(BuildContext context) {
return Container(
// ....
);
}
}
查看 示例 获取更多关于编写 reactive
的示例,或者直接浏览 源码,它非常简洁。
与 flutter_hooks
的比较
从用户的角度来看,flutter_hooks
是对 StatefulWidget
的替代。而 reactives
并不是。如果你查看 ReactiveHostMixin
的代码,你会发现它只有大约 60 行(包括空行)。reactives
并不试图替代 StatefulWidget
,它只是解决了由于 mixin 的“is-a”关系而导致的可重用性问题。reactives
采用的是“has-a”关系。
编写 reactives
没有新的规则。查看现有的 reactives
示例即可。基本上就是将相同的逻辑隔离到不同的类中。
因此,它不需要像 useState
这样的大量钩子,因为如果尝试替代 StatefulWidget
,则需要这些钩子。
学习 reactives
几乎不需要什么成本。hooks
需要你学习一些概念以及如何或不如何做某些事情。它还要求你完全改变整个小部件。reactives
即使对于单个小部件也可以逐步适应。
示例代码
以下是 reactives
的一个简单示例,展示了如何在 Flutter 中使用 reactives
。
import 'package:flutter/material.dart';
import 'package:reactives/reactives.dart';
/// 简单的展示 reactive 的小部件
class LoginWidget extends StatefulWidget {
const LoginWidget({Key? key}) : super(key: key);
[@override](/user/override)
_LoginWidgetState createState() => _LoginWidgetState();
}
// 添加 ReactiveHostMixin
class _LoginWidgetState extends State<LoginWidget> with ReactiveHostMixin {
// 创建所需的 reactive
late final emailCtrl = ReactiveTextEditingController(this).ctrl;
late final passwordCtrl = ReactiveTextEditingController(this).ctrl;
var passwordVisible = false;
void submit() {
// 登录逻辑
}
void toggeVisible() {
setState(() {
passwordVisible = !passwordVisible;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// 像任何字段一样使用 reactive
TextField(controller: emailCtrl),
TextField(
controller: passwordCtrl,
decoration: InputDecoration(
suffix: IconButton(
icon: const Icon(Icons.visibility),
onPressed: toggeVisible,
),
),
obscureText: !passwordVisible,
),
ElevatedButton(
child: const Text('登录'),
onPressed: submit,
),
],
);
}
}
/// ReactiveLogin 是一种方法,可以将登录逻辑从小部件中提取出来,以便于测试和复用
class ReactiveLogin extends Reactive {
final ReactiveTextEditingController _email;
final ReactiveTextEditingController _password;
TextEditingController get emailCtrl => _email.ctrl;
TextEditingController get passwordCtrl => _password.ctrl;
bool _passwordVisible = false;
bool get passwordVisible => _passwordVisible;
ReactiveLogin(ReactiveHost host)
: _email = ReactiveTextEditingController(host),
_password = ReactiveTextEditingController(host),
super(host);
void submit() {
// 登录逻辑
}
void toggleVisible() {
_passwordVisible = !_passwordVisible;
host.requestUpdate(); // 调用 setState
}
}
/// 上面的示例可以通过提取的登录逻辑重新编写
/// 这减少了小部件的 UI 逻辑
class LoginView extends StatefulWidget {
const LoginView({Key? key}) : super(key: key);
[@override](/user/override)
_LoginViewState createState() => _LoginViewState();
}
// 添加 ReactiveHostMixin
class _LoginViewState extends State<LoginView> with ReactiveHostMixin {
// 创建所需的登录 Reactive
late final login = ReactiveLogin(this);
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// 像任何字段一样使用 reactive
TextField(controller: login.emailCtrl),
TextField(
controller: login.passwordCtrl,
decoration: InputDecoration(
suffix: IconButton(
icon: const Icon(Icons.visibility),
onPressed: login.toggleVisible,
),
),
obscureText: !login.passwordVisible,
),
ElevatedButton(child: const Text('登录'), onPressed: login.submit),
],
);
}
}
更多关于Flutter响应式编程插件reactives的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter响应式编程插件reactives的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,响应式编程是一种强大的范式,用于处理应用状态的变化。reactives
插件(虽然这不是一个官方或广泛认知的插件名,我假设你指的是一种响应式编程的实现或类似 provider
、riverpod
、get_it
等状态管理库的替代方案)可以帮助你更有效地管理这些状态变化。不过,由于 reactives
并非一个标准的 Flutter 库名,我将基于 Flutter 社区中常见的响应式编程实践,给出一个使用 provider
库进行响应式编程的代码案例。
provider
库是 Flutter 社区中非常流行的状态管理解决方案之一,它允许你在 widget 树中共享和监听数据,当数据变化时,相关的 UI 会自动重建。
以下是一个使用 provider
库进行响应式编程的简单示例:
-
添加依赖: 首先,在你的
pubspec.yaml
文件中添加provider
依赖:dependencies: flutter: sdk: flutter provider: ^6.0.0 # 请检查最新版本号
-
创建一个 ChangeNotifier 类: 这个类将持有我们的应用状态,并在状态改变时通知监听者。
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class Counter with ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } }
-
设置 MultiProvider: 在
main.dart
中,使用MultiProvider
将我们的Counter
提供给应用。import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'counter.dart'; // 假设我们的 ChangeNotifier 类在 counter.dart 文件中 void main() { runApp( MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => Counter()), ], child: MyApp(), ), ); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ); } }
-
在 UI 中消费状态: 使用
Consumer
或Selector
widget 来监听Counter
的变化,并更新 UI。import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Demo Home Page'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), Consumer<Counter>( builder: (context, counter, child) => Text( '${counter.count}', style: Theme.of(context).textTheme.headline4, ), ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: () { final counter = Provider.of<Counter>(context, listen: false); counter.increment(); }, tooltip: 'Increment', child: Icon(Icons.add), ), ); } }
在这个示例中,我们创建了一个 Counter
类来管理计数器的状态,使用 ChangeNotifierProvider
将其提供给整个应用。然后,在 MyHomePage
中,我们使用 Consumer
widget 来监听 Counter
的变化,并在按钮点击时更新状态。
尽管 reactives
不是一个标准的 Flutter 库名,但上述代码示例展示了如何在 Flutter 中使用响应式编程原则,通过 provider
库来管理应用状态。如果你指的是一个特定的第三方库,请确保你提供了正确的库名,以便给出更精确的代码示例。