Flutter响应式编程插件flutter_reactive_widget的使用

Flutter响应式编程插件flutter_reactive_widget的使用

已弃用

我正在弃用此库,因为我发现了一个在Flutter中创建响应式UI的更简单且更好的机制:请改用flutter_reactive_value库。

flutter_reactive_widget库的文档和代码仍会托管在此处,但此代码将不再进行进一步开发。

使用

此库提供了一种在Flutter中创建响应式UI的简单机制。

1. 声明状态

使用ReactiveValue<T>(继承自ValueNotifier<T>)声明您的状态:

final counter = ReactiveValue&lt;int&gt;(0);

2. 包装需要对counter.value变化作出反应的代码

使用ReactiveWidget(它接受一个零参数lambda,在ReactiveWidgetbuild方法中调用该lambda)包装任何需要对counter.value的变化作出反应的代码。

如果在ReactiveWidgetbuild()方法运行时读取了counter.value,那么ReactiveWidget将开始监听counter.value的变化。(如果该部件被销毁,此监听器将自动移除。)

ReactiveWidget(
  () =&gt; Text('${counter.value}'),
),

3. 修改counter.value的事件处理程序将触发ReactiveWidget重新构建

修改counter.value的事件处理程序现在将通过在后帧回调中调度setState调用来触发ReactiveWidget重新构建。

IconButton(
  icon: const Icon(Icons.plus_one),
  onPressed: () {
    counter.value++;
  },
),

counter.value可以在除build方法之外的任何地方修改(因为build方法不应该改变状态)。

添加库依赖

flutter_reactive_widget托管在pub.dev上。

要能够导入该库,你需要在pubspec.yaml中添加对该库的依赖(如果你想要控制版本,可以将any替换为最新版本),然后运行flutter pub get

dependencies:
  flutter:
    sdk: flutter
  flutter_reactive_widget: any

在你的代码中导入该库:

import 'package:flutter_reactive_widget/flutter_reactive_widget.dart';

持久化状态的子类PersistentReactiveValue

ReactiveValue每次应用重启时都会重置为其初始值。你可以通过使用PersistentReactiveValue而不是ReactiveValue来持久化值。

首先,在main函数中,你需要初始化WidgetsFlutterBinding,然后需要调用await initPersistentReactiveValue()(定义在flutter_reactive_widget.dart中),这会启动SharedPreferences并从存储中加载任何持久化的值。

main() async {
  // 需要按以下顺序执行这两行代码
  WidgetsFlutterBinding.ensureInitialized();
  await initPersistentReactiveValue();
  
  // 然后运行应用
  runApp(App());
}

然后你可以使用PersistentReactiveValue而不是ReactiveValue

final counter = PersistentReactiveValue&lt;int&gt;(
      /* key */ 'counter', /* defaultValue */ 0);

counter.value如果没有被设置过,则会被设置为默认值0;但如果在之前的某个应用运行中已经设置了值,那么这个值将从SharedPreferences中恢复,使用键’counter’

每当在未来设置counter.value时,不仅任何包裹的ReactiveWidget会被更新,而且新值还会异步写入到SharedPreferences持久化缓存中,使用相同的键。

可以存储null值的子类PersistentReactiveNullableValue

注意,对于PersistentReactiveValue<T>T不能是可空类型(T?),因为null值无法与SharedPreferences中不存在的值区分开来。

如果你希望能够在SharedPreferences中存储null值(这相当于尝试设置null值时从SharedPreferences中删除键),则可以使用PersistentReactiveNullableValue<T?>。对于此类,defaultValue是可选的。

用于验证的子类ValidatingReactiveValue

ValidatingReactiveValueReactiveValue的一个子类,具有一个额外的字段validationError,它本身是一个ReactiveValue<String?>。每当ValidatingReactiveValue的值发生变化时,validationError字段会通过调用传递给ValidatingReactiveValue构造函数的validate函数来更新。例如:

final age = ValidatingReactiveValue&lt;int?&gt;(null,
        (a) =&gt; a == null ? 'Please specify age' : null);

// 现在你可以在一个`ReactiveWidget`中监听`age.validationError`或`age.value`

手动通知深层值的变化

如果你创建了final set = ReactiveValue<Set<String>>({});然后调用了set.value.add(‘abc’)set的监听器不会收到更改的通知,因为引用本身(即set.value)没有改变。在这种情况下,你可以手动调用监听器,例如:

_addFlag(bool flag) {
  bool changed = flag ? set.value.add('flag') : set.value.remove('flag');
  if (changed) {
    set.notifyListeners();
  }
}

在StatefulWidget的State.dispose()方法中移除ReactiveValue监听器

如果你在一个StatefulWidgetState<T>对象的字段中实例化了一个ReactiveValue,确保你的State<T>dispose()方法调用了ReactiveValuedispose()方法来移除所有监听器,当部件被销毁时,以防止内存泄漏。

生命周期和状态存储位置

如果你想让ReactiveValue在整个应用生命周期内存在,可以参考这篇Medium文章中关于如何使用GetIt组织应用状态的好建议。应用于flutter_reactive_widget

main.dart

main中调用setUpGetIt()

import 'package:my_app/pages/home_page.dart';
import './service_locator.dart';

main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await initPersistentReactiveValue();

  // 注册状态单例(定义在service_locator.dart)
  setUpGetIt();

  runApp(HomePage());
}

service_locator.dart

使用GetIt将所有包含状态的类注册为单例,每个页面一个状态类(即为页面home_page.dart创建home_page_state.dart):

import 'package:my_app/pages/home_page_state.dart';
import 'package:get_it/get_it.dart';

final getIt = GetIt.instance;

void setUpGetIt() {
  getIt.registerLazySingleton&lt;HomePageState&gt;(() =&gt; HomePageState());
}

pages/home_page_state.dart

定义每个状态类:

import 'package:flutter_reactive_widget/flutter_reactive_widget.dart';

/// HomePage的持久状态
class HomePageState {
  final count = PersistentReactiveValue&lt;int&gt;('count', 0);
}

pages/home_page.dart

使用GetIt.instance<T>()(或getIt<T>,如果你导入了service_locator.dart)获取你需要读取状态的状态单例类实例:

import 'package:my_app/pages/home_page_state.dart';
import 'package:flutter_reactive_widget/flutter_reactive_widget.dart';
import 'package:flutter/material.dart';
import './service_locator.dart';

// 获取页面的状态
final _homePageState = getIt&lt;HomePageState&gt;();

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('HomeView'),
        centerTitle: true,
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          ReactiveWidget(
            () =&gt; Text(
              '${_homePageState.count.value}',
              style: const TextStyle(fontSize: 20),
            ),
          ),
          IconButton(
            icon: const Icon(Icons.plus_one),
            onPressed: () {
              _homePageState.count.value++;
            },
          ),
        ],
      ),
    );
  }
}

更多关于Flutter响应式编程插件flutter_reactive_widget的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter响应式编程插件flutter_reactive_widget的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用Flutter响应式编程插件flutter_reactive_widget的代码案例。这个插件使得在Flutter中进行响应式编程变得更加简单和直观。

首先,确保你已经在pubspec.yaml文件中添加了flutter_reactive_widget依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_reactive_widget: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

以下是一个简单的示例,展示如何使用flutter_reactive_widget进行响应式编程。在这个例子中,我们将使用ReactiveTextField来创建一个响应式文本字段,并实时显示输入内容。

import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; // 注意:实际包名可能有所不同,这里仅作为示例
import 'package:reactive_forms/reactive_forms.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _formGroup = fb.group({
    'username': ['', Validators.required],
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Reactive Widgets Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: ReactiveForm(
          formGroup: _formGroup,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              ReactiveTextField<String>(
                formControlName: 'username',
                decoration: InputDecoration(
                  labelText: 'Username',
                ),
              ),
              SizedBox(height: 16),
              Text(
                'You entered: ${_formGroup.value['username'] ?? ''}',
                style: TextStyle(fontSize: 18),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

在这个例子中,我们做了以下几件事情:

  1. 创建表单组:使用fb.group创建一个表单组,并定义了一个名为username的表单控件,它有一个初始值和一个验证器(Validators.required)。

  2. 构建UI:使用ReactiveForm包装表单,并在其内部使用ReactiveTextField创建一个响应式文本字段。formControlName属性将文本字段与表单组中的username表单控件绑定。

  3. 显示输入内容:通过访问_formGroup.value['username']实时显示用户输入的内容。

注意:flutter_reactive_widget插件实际上依赖于reactive_forms库来处理表单控件和验证。因此,确保你也添加了reactive_forms依赖。

dependencies:
  reactive_forms: ^x.y.z  # 请替换为最新版本号

这个示例展示了如何使用flutter_reactive_widget(通过reactive_forms)进行基本的响应式表单编程。你可以根据需求扩展这个示例,添加更多的表单控件和验证逻辑。

回到顶部