MoLc is my own state management library based on Provider encapsulation. It is currently used for a small business project with 2w daily activities. The performance is not bad. I will share it with you.
MoLc is a combination of Model and Logic, designed to separate data model and business logic. I came from Android, and the MVP model was quite popular back then, so when I first came into contact with Flutter, I made such a package, which is the first version of MoLc. Let’s talk about what MoLc has achieved. Personally, I think MoLc is suitable for most medium and large-scale projects. Welcome to come to guide the shortcomings.
Learn about Model
and before using MoLc Logic
.
Model
Model
It is the class that stores the Widget state, which can be used directly
class TestModel extends Model {}
复制代码
If you want to Model
use it in context
, for example, you need to context
get the text through S.of(context)
, then use a subclassWidgetModel
class Test1Model extends WidgetModel {}
复制代码
context
Get the upper layer context
in Model
the sub context.read<T>()
, which is provided by the Provider, and everyone should be familiar with it.
- refresh
test1Model.refresh();
复制代码
- Selector
Different from Provider 's Selector, MoLc's Selector is used for refined refresh.
MixingSelectorMixin<T>
class TestModel extends Model with SelectorMixin<Tuple3>{}
复制代码
Implement the T selectWith();
method , whether the return value changes or not determines whether the Model is refreshed.
@override
Tuple3<int, String, bool> selectWith() {
return Tuple3(this.field1, this.field2, this.field3);
}
复制代码
Logic
Logic
is a class that stores business logic, using
class TestLogic extends Logic {}
复制代码
同样可以在子context
中获取上层context的Logic
,也是用context.read<T>()
。 Logic
也提供了子类WidgetLogic
用于获取context
。
另外,Logic还提供了MoLogic
提供Model
,但不建议在普通业务逻辑函数中使用,不然数据模型和业务逻辑分离的初衷就被破坏了。仅建议在dispose
中使用model,用来执行一些页面或者小组件销毁时需要的逻辑。
MoLcWidget
MoLc的核心组件是 ModelWidget
、LogicWidget
、MoLcWidget
,前两个适合只有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链接,感兴趣可以尝试一下。