MoLc —— Flutter状态管理组件

MoLc是我自己基于Provider封装的一个状态管理的库,目前用于一个2w日活的小商业项目,表现还算可以,拿出来和大家分享一下。
MoLc是Model、Logic的组合,旨在分离数据模型和业务逻辑。我是Android出身,MVP模式在当年还算火热,所以刚接触Flutter就做了这样一个封装,也就是MoLc的初版。下面来讲讲MoLc实现了什么,个人觉得MoLc适合大部分中大型项目,欢迎大佬前来指导不足之处。

使用MoLc之前要了解ModelLogic

Model

Model是存放Widget状态的类,直接使用

class TestModel extends Model {}
复制代码

如果你想要在Model中使用context,比如需要通过context获取文本S.of(context),那么使用子类WidgetModel

class Test1Model extends WidgetModel {}
复制代码

在子context中获取上层contextModelcontext.read<T>(),这是Provider提供的,大家应该很熟悉。

  • 刷新
test1Model.refresh();
复制代码
  • Selector

不同于Provider的Selector,MoLc的Selector是用于精细化刷新。

混入SelectorMixin<T>

class TestModel extends Model with SelectorMixin<Tuple3>{}
复制代码

实现 T selectWith();方法, 返回值的是否改变决定了Model是否刷新。

@override
Tuple3<int, String, bool> selectWith() {
  return Tuple3(this.field1, this.field2, this.field3);
}
复制代码

Logic

Logic是存放业务逻辑的类,使用

class TestLogic extends Logic {}
复制代码

同样可以在子context中获取上层context的Logic,也是用context.read<T>()Logic也提供了子类WidgetLogic用于获取context
另外,Logic还提供了MoLogic提供Model,但不建议在普通业务逻辑函数中使用,不然数据模型和业务逻辑分离的初衷就被破坏了。仅建议在dispose中使用model,用来执行一些页面或者小组件销毁时需要的逻辑。

MoLcWidget

MoLc的核心组件是 ModelWidgetLogicWidgetMoLcWidget,前两个适合只有Model或者Logic的Widget,用的比较少,重点讲一下MoLcWidget,下面是MoLcWidget的写法:

class ExamplePage extends StatelessWidget {
  const ExamplePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MoLcWidget<_ExampleModel, _ExampleLogic>(
      modelCreate: (_) => _ExampleModel(),
      logicCreate: (_) => _ExampleLogic(),
      init: (_, model, logic) => logic.init(model),
      builder: (context, model, logic, __) => Container(),
    );
  }
}

class _ExampleModel extends Model {}

class _ExampleLogic extends Logic {
  void init(_ExampleModel model) {}
}
复制代码

如同Provider一样,还是有些样板代码,不过可以使用IDE的Live Template,也还算方便。MoLc把model和logic从Widget里分离出去,你可以在model里定义Widget的状态,可以在logic写Widget逻辑代码,然后在MoLcWidget里面调用。看到这里你可能觉得没什么,只是对Provider的一层封装而已,没错,这就是他的第一个版本的基本功能。

TopProvider

接下来说数据共享,很多使用Provider的人可能用的最多的反而是处于APP之上的顶级Model,像这样:

MultiProvider(
      providers: ...,     
      child: MaterialApp(
        ...
      ),
    ),
复制代码

这是由于InheritedWidget的特性,context节点位置要位于MaterialApp 之上才能让App中的所有路由页面访问到,才能实现跨页面传输数据。这里MoLc封装了一层TopProvider,用于内部的一些全局容器的实现和更方便的访问TopModel

TopProvider(
  providers: ...,
  child: MaterialApp(
    ...
  ),
),
复制代码

TopModel

  • 全局获取

在MoLc中,顶级Mode被命名为TopModel,继承于Model,在上述TopProvider里注册。你几乎可以在任意地方通过顶级函数top<T>()来获取你需要的TopModel,而不需要传入context

  • 局部刷新

在实际项目中顶级Model带来了另一个问题,顶级Model的刷新会导致整个App的build,也就是性能问题。为了解决这个问题,MoLc定义了一个名为EventModel<T>Mixin,T为Event的类型。

你可以给为你的TopModel定义一个enum的Event:

enum TestEvent { event1, event2, event3 }
复制代码

然后TopModel混入EventModel<T>

class TestTopModel extends TopModel with EventModel<TestEvent> {}
复制代码

需要监听的Model混入EventConsumerMixin

class Test2Model extends Model with EventConsumerForModel {}
复制代码

Model监听Event

model.listenTopModelEvent(TestEvent.event4);
复制代码

TopModel发送Event

testTopModel.refreshEvent(TestEvent.event4)
复制代码

这样就完成的TopModel对于需要监听部分事件Model的局部刷新。

ExposedMixin

上面提到过InheritedWidget的特性,只能实现子context对于父context的数据访问。而实际在业务中,我们常常会遇到父context访问子context的需求,或者需要兄弟context相互访问。MoLc也提供了这样的实现,只需要混入一个ExposedMixin

Model混入ExposedMixin

class Test3Model extends Model with ExposedMixin {}
复制代码

然后你就可以在任意地方通过顶级函数find<T>()获取到这个Model,如果这个Model当前不存在或者已经disposed是获取不到的。

Logic混入ExposedMixin

class Test3Logic extends Logic with ExposedMixin {}
复制代码

此时的Logic你可以在任意地方进行调用,轻松的实现了Logic的复用。这里有一个TODO:未注册在BuildContext中的Logic的调用,目前只能调用当前APP的BuildContext树中存在的Logic

最后放上pub链接,感兴趣可以尝试一下。

猜你喜欢

转载自juejin.im/post/7082604401801560095