全面解读Flutter状态管理框架signals使用,知其然和所以然

signals有多简单

signals到底有多简单。

  1. 可以通过signal发送一个信号。
  2. 可以通过computed组合计算多个signal。
  3. 可以通过effect监听数据变化。 示例代码如下:
dart 复制代码
import 'package:signals/signals.dart';


void main() {
  final name = signal("Jane");
  final surname = signal("Doe");
  final fullName = computed(() => name.value + " " + surname.value);

// Logs: "Jane Doe"
  effect(() {
    print("name is ${name.value}");
    print("fullName is ${fullName.value}");
  });
// Updating one of its dependencies will automatically trigger
// the effect above, and will print "John Doe" to the console.
  name.value = "John";

}

运行结果如下图所示:

分配两个Signal:name和surname,一个Computed(fullName)是name和surname计算结果,effect内部监听数据变化打印name和fullName的值。当name的值被重新设置的时候,fullName的值是name和surname的组合计算,也会跟随重新计算。

Computed图解

Computed会注册监听多个Signal,当其中的任何一个Signal值变化的时候,都会把值通知Computed从而引起Computed值的变换。注意上面图的箭头方向代表数据流向。

Effect

你也可以从effect中返回一个清理函数。当effect被销毁时,该函数会被调用。清理函数以阻止订阅更新回调。

scss 复制代码
  final s = signal(0);

  final dispose1 = effect(() {
    print(s.value);
    return () => print('Effect destroyed');
  });

  // Destroy effect and subscriptions
  dispose1();
  s.value = 2;

运行结果如下图所示:只打印了一次s的值,dispose1函数执行以后,就不再监听s的数据变化。

需要注意effect使用过程中防止发生无限循环问题:不能在effect函数体中改变signal的值,否则会无限循环导致不可处理异常。

Batch

批处理功能允许您将多个信号写入组合成一个更新,该更新在回调完成时触发。

scss 复制代码
  final counter = signal(0);
  final _double = computed(() => counter.value * 2);
  final _triple = computed(() => counter.value * 3);
  effect(() {
    print(_double.value);
    print(_triple.value);
  });

  batch(() {
    counter.value = 1;
    // Logs: 2, despite being inside batch, but `triple`
    // will only update once the callback is complete
    print(_double.value);
  });
// Now we reached the end of the batch and call the effect

batch执行完成后才会执行effect。batch可以嵌套,并且当最外层批次调用完成时,更新将被刷新。运行结果如下图所示:

Flutter中的应用

在Flutter中,如果你想创建一个signal,当Widget从Widget树中移除时,该signal会自动释放,并在signal发生变化时重建Widget,你可以在有状态Widget中使用createComputed。示例代码如下:

scala 复制代码
import 'package:flutter/material.dart';
import 'package:signals/signals_flutter.dart';

void main() async {
  runApp(CounterWidget());
}

class CounterWidget extends StatefulWidget {
  @override
  _CounterWidgetState createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> with SignalsMixin {
  late final counter = createSignal(0);
  late final isEven = createComputed(() => counter.value.isEven);
  late final isOdd = createComputed(() => counter.value.isOdd);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Counter: even=$isEven, odd=$isOdd'),
            ElevatedButton(
              onPressed: () => counter.value++,
              child: Text('Increment'),
            ),
          ],
        ),
      ),
    ),);
  }
}

无需Watch Widget或扩展程序,当Widget从Widget树中移除时,signal将自动处置。SignalsMixin是一个混合类,当Widget从Widget树中移除时,它会自动处置在该状态下创建的signal。

总结

signals是一种存储状态的方式,当值发生变化时自动通知监听器,而不需要setState、Provider或其他重量级解决方案。可以通过signal发送一个信号,可以通过computed组合计算多个signal,可以通过effect监听数据变化,可以通过Batch批量处理多个signal的值。signals使用起来还是挺简单的,但是signals的原理需要下篇来讲解。希望文章对您有帮助,祝大家编码愉快。

参考资料

dartsignals.dev/ pub.dev/packages/si... dartsignals.dev/reference/o...

相关推荐
pengyu5 小时前
【Flutter 状态管理 - 柒】 | InheritedWidget:藏在组件树里的"魔法"✨
android·flutter·dart
肥肥呀呀呀6 小时前
flutter 小知识
flutter
玫瑰花开一片一片11 小时前
Flutter IOS 真机 Widget 错误。Widget 安装后系统中没有
flutter·ios·widget·ios widget
hepherd12 小时前
Flutter 环境搭建 (Android)
android·flutter·visual studio code
bst@微胖子1 天前
Flutter之路由和导航
flutter
亚洲小炫风1 天前
flutter 中各种日志
前端·flutter·日志·log
louisgeek1 天前
Flutter 动画之 Implicit 隐式动画
flutter
勤劳打代码1 天前
游刃有余 —— Isolate 轻量化实战
flutter·github·dart