前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter与MobX的那些事

Flutter与MobX的那些事

作者头像
烧麦程
发布2022-05-10 20:38:45
8070
发布2022-05-10 20:38:45
举报
文章被收录于专栏:半行代码半行代码

开始

在以前的一篇文章中,半行代码 介绍到在 Flutter 里面使用 MobX, 今天我们就来聊聊 Flutter 和 MobX 的那些事。

这篇文章的大部分内容可以在 MobX.dart[1] 中看到更原汁原味的介绍。阅读本篇文章阅读约需 30 分钟。

我们先来看看 MobX 是什么,根据README的介绍

代码语言:javascript
复制
使用透明的函数响应式编程增强 Dart 程序中的状态管理

是前端里大名鼎鼎的 MobX.js 的 Dart 版本。

概念

那么,MobX.Dart 有哪些概念,反应了自己函数响应式编程的特性呢?

这里关系到 MobX 的 3 个重要概念:

?Observables: Observables 表示响应式的状态。状态很容易理解,就是应用程序里面的状态,或者数据。响应式,就是可以感知到,可观察到数据的变化,也就是我们经常接触到的 观察者模式

?Actions: Actions 就是一系列可以引发状态发生变化的动作

?Reactions:上面提到状态是可观察的,那么这里的 Reactions 就是状态的观察者,状态发生改变的时候,他们可以收到数据变化的通知。

关于 Observables,还有一些更多的概念:

Computed Observables

顾名思义,被计算出来的 Observables。在一个应用中,我们实际上有 2 种状态,这里分别称为 core-statederived-statecore-state 指的就是一个对象原本就存在的状态,例如一个人有自己的firstname和lastname,姓和名是人固有的状态。那么 firstname + lastname,就动态的出来了我们”姓名“的结果。这个就是我们的 derived-state。当然这里是一个很基础的例子,现实中我们的业务可能是几个固有属性,通过一个复杂的计算算出了一个最终的结果。这个最终结果实际上也是这个对象的一种状态,它也需要被感知到变化。

这里套用 MobX 的一张图来表示他的核心概念:

show code

我们来看看 Mobx 的具体用法,套用 Flutter 默认的 计数器点击 +1 的例子。

一个简单的计数器可以表示成一个可观察的数字状态,计数器表示为 Counter 对象:

代码语言:javascript
复制
part 'counter.g.dart';

class Counter = CounterBase with _$Counter;

abstract class CounterBase with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }
}

这里,Mobx 需要借助 builder_runner 这个库生成对应的 _$Counter 类的代码。具体可以自行 Google。

那么示例中计数器的值怎么反应到 UI 呢?这里就要借助我们 Flutter-MobX 里的 Widget 啦

代码语言:javascript
复制
final counter = Counter(); // Instantiate the store

Observer(
    builder: (_) => Text('${counter.value}',
    style: Theme.of(context).textTheme.display1,
    ),
),

这里我们使用了一个叫做 Observer 的 Widget, builder方法里面把 counter 的 observable 对象的值作为属性传给 Text。

这里在调用 @action 的函数之后,counter 里面的值变化后会自动体现在 UI 上。

这里我们可以看到,使用了 MobX,我们可以尽可能的使用 StatelessWidget,避免了 setState 的混乱。也提升了效率。

那么如何使用 Reaction 完成对他的监听呢,Reaction相关的函数有好几个,这里列举几个比较典型的:

ReactionDisposer autorun(Function(Reaction) fn)

立即执行 fn

代码语言:javascript
复制
import 'package:mobx/mobx.dart';

String greeting = Observable('Hello World');

final dispose = autorun((_){
  print(greeting.value);
});

greeting.value = 'Hello MobX';

dispose();

这里会输出

代码语言:javascript
复制
Hello World
Hello MobX

ReactionDisposer reaction<T>(T Function(Reaction) predicate, void Function(T) effect)

监听 predicate 里面监听 observable,当 predicate 返回了新的对象的时候,调用 effect 函数。

代码语言:javascript
复制
import 'package:mobx/mobx.dart';

String greeting = Observable('Hello World');

final dispose = reaction((_) => greeting.value, (msg) => print(msg));

greeting.value = 'Hello MobX'; // Cause a change

dispose();

输出:

代码语言:javascript
复制
Hello MobX

ReactionDisposer when(bool Function(Reaction) predicate, void Function() effect)

待条件的响应。在reaction的基础上加上 predicate 函数返回 true

最佳实践

使用了 MobX,那么我们的代码该如何组织呢?一般来说,我们的 Store 会按照职责,分到每个业务相关的 Store 去。

那么,一个业务模块,如何组织它和 UI、逻辑呢?官方给出了建议的方式。将 Widegt - Store - Service 结合在一起。

?Widget:UI,状态的可视化表示?Store:处理状态?Service:逻辑操作,包括复杂逻辑,网络请求,本地数据库存储等等

最佳的代码结构如下:

其中:

UI 层应该尽量使用 StatelessWidgetObserver 结合, 减少 Widget 的 rebuild 次数,提升性能。

Store里面放的 @observable 对象,因为 Dart 在 Flutter 是不能进行运行时反射的,所以复杂对象需要我们自己进行 observable 的声明。否则不会生效。当需要处理衍生状态的时候,可用 computed 替代。

到这里,其实我们在使用 MobX 的时候可以组织出职责分层很明确的函数响应式应用架构。但是不同的页面如何持有 Store 对象,也成了一个问题,当然这个问题在所有的分层架构里都存在。

最简单的是直接写单例的 store, 但是单例的弊端非常明显。我们需要的是在这几个页面这个对象是同一个,超出这个范围,对象可以销毁,或者使用的是另一个对象。很直接的我们就会需要一个对象管理框架,即 依赖注入

针对这点,官方也给出了自己的建议,可以使用 Provider 这个框架达到依赖注入的目的。在他的官方文档介绍里,也说自己是一个介于 DI 和 状态管理之间的框架。在这篇文章就不赘述 Provider的使用,感兴趣的朋友可以查看:provider的文档[2]

小结

使用 MobX,我们可以快速的上手,用一种很简便,容易组织的方式进行 Flutter 的状态管理和代码架构的统一。而且 Store 天然的分开可以写一堆。不会存在 Redux 顶级状态管理难以分而治之的问题。对于异步场景的处理也比 Redux 简单。比较推荐给大家。

References

[1] MobX.dart: https://mobx.pub/getting-started [2] provider的文档: https://pub.dartlang.org/packages/provider

本文参与?腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-01-11,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 半行代码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体同步曝光计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 开始
  • 概念
  • Computed Observables
  • ReactionDisposer autorun(Function(Reaction) fn)
  • ReactionDisposer reaction<T>(T Function(Reaction) predicate, void Function(T) effect)
  • ReactionDisposer when(bool Function(Reaction) predicate, void Function() effect)
  • 最佳实践
  • 小结
  • References
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com