昨天稍微提到了状态管理及 MobX 的基本介绍那今天就要来说明 MobX 中的核心概念。
MobX 最重要的就是这三个东西: Observables、Actions、Reactions
就是我们昨天提到的被观察者,也就是在这个程序中的 reactive-data ,当 Observables 被改变时会通知监听这个Observable的观察者。
则是我们实作「要如何更改 Observable 」 的方法,我们如果要变更 Observable 只能透过 Actions。
reaction 会针对observables
的任何变动做出回应,像是我们可以使用 when
让我们某个 observables
变成特定的值时就做出额外的动作。
而其实MobX提供的Observer Widget
也算是 Reaction 的一种,因为他追踪了observables
的变动当他有更新时就会重新build
在程序码中他们长得像这样:
import 'package:mobx/mobx.dart';
part 'counter.g.dart';
class Counter = CounterBase with _$Counter;
abstract class CounterBase with Store {
@observable
int value = 0;
@action
void increment() {
value++;
}
}
我们在一个 abstract class
中宣告了一个值及function 我们只要分别加上 @observable
、@action
这两个decorator 就能完成这件事情。
当然你会想为什麽会有 with _$Counter
、 part 'counter.g.dart'
等等奇怪的东西,其实这些decorator 是为了让 MobX_codegen 让我们产生 observable 以及 action 的内部实作:
class Counter {
Counter() {
increment = Action(_increment);
}
final _value = Observable(0);
int get value => _value.value;
set value(int newValue) => _value.value = newValue;
Action increment;
void _increment() {
_value.value++;
}
}
如果不套用 MobX_codegen 的就要手动写这些code。
但需要搭配codegen 算是MobX的缺点之一,代表你每次存档後要等一段时间让 codegen 将MobX的code产生出来,虽然时间很短但终究会有被打断的感觉。
那我们就开始将MobX套入我们的专案吧
就在 pubspec.yaml 新增套件:
dependencies:
# ... 省略其他
mobx: ^2.0.4
flutter_mobx: ^2.0.2
# ... 省略其他
dev_dependencies:
# ... 省略其他
build_runner: ^2.1.4
mobx_codegen: ^2.0.3
# ... 省略其他
然後新增一个档案todo_view_model.dart
把我们在 setState
的实作搬到这里,然後将 List
改为 ObservableList
,这两者差距其实在这个专案是看出不来的,最主要是差在说如果单纯是 List
的话里面的元素变化时并不会被监听,除非是整个 List
有变化之类的。
import 'package:mobx/mobx.dart';
import 'package:todolist/model/todo_model.dart';
part 'todo_view_model.g.dart';
class TodoViewModel = _TodoViewModel with _$TodoViewModel;
abstract class _TodoViewModel with Store {
@observable
ObservableList<TodoModel> todoList =
ObservableList.of([TodoModel(content: '123')]);
@action
void removeTodo(int hashCode) {
todoList =
ObservableList.of(todoList.where((todo) => todo.hashCode != hashCode));
}
@action
void addTodo(String input) {
todoList = ObservableList.of([...todoList, TodoModel(content: input)]);
}
@action
void toggleStatus(int hashCode) {
todoList = ObservableList.of(todoList.map((todo) {
if (todo.hashCode == hashCode) {
todo.isDone = !todo.isDone;
return todo;
} else {
return todo;
}
}));
}
}
然後在terminal 输入:
flutter pub run build_runner watch
让 MobX codegen 可以产生我们要的程序码。
这样我们就不需要使用 setState
了在main.dart里面就会变成:
final todoViewModel = TodoViewModel();
void _handleAddNewTodo(String input) {
todoViewModel.addTodo(input);
_textEditingController.text = '';
}
void _handleRemoveTodo(int hashCode) {
todoViewModel.removeTodo(hashCode);
}
void _handleToggleStatus(int hashCode) {
todoViewModel.toggleStatus(hashCode);
}
然後使用 Observer
包住我们要动态更新的部分
Observer(
builder: (_) {
return Column(
children: [
// ... 省略
],
);
},
);
}
@computed
会对一个 observables
监听後产生一个衍生的值,像是当我们想取得不同状态的 todoList
,就可写成这样:
@computed
ObservableList<TodoModel> get completedTodos =>
ObservableList.of(todoList.where((todo) => todo.isDone == true));
@computed
ObservableList<TodoModel> get pendingTodos =>
ObservableList.of(todoList.where((todo) => todo.isDone != true));
程序码:
https://github.com/zxc469469/flutter_todo_list/tree/Day21
今天大概说明了 MobX 基本用法,那这个小专案也差不多到这里结束。
明天开始来串接API的部分
>>: Day20 让电脑透过数据机和有线、无线网路传递讯息
条件式就是小学常写的造样造句:如果...就(否则)...的概念。 这边会介绍几种常用的条件式语句 i...
本文内容 本篇内容为阅读官方文件 ngStyle 的笔记内容。 ngStyle 使用时机 昨天 Da...
在Day7时候有提到排序法的简介,并且简介常见的6个演算法,在Icebear学习5天JS语法之後,在...
才刚提到趋势科技去年在 MITRE Engenuity 的 ATT&CK Evaluatio...
在昨天介绍了Helm这一工具,那们今天就来介绍如何建立属於自己的Helm repo吧!! ps.如果...