Mobx4 核心概念

使用 MobX 将一个应用变成响应式的可归纳为以下三个步骤:

Step1:定义状态并使其可观察

可以使用任何数据结构来存储状态(如对象、数组、类)。只要确保所有会随时间流逝而改变的属性打上 mobx 的标记使它们变得可观察即可。

1
2
3
4
import { observable } from "mobx";
var appState = observable({
timer: 0,
});

Step2:创建视图以响应状态的变化

通常来说,任何函数都可以成为可以观察自身数据的响应式视图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { observer } from "mobx-react";
@observer
class TimerView extends React.Component {
render() {
return (
<button onClick={this.onReset.bind(this)}>
Seconds passed: {this.props.appState.timer}
</button>
);
}
onReset() {
this.props.appState.resetTimer();
}
}
ReactDOM.render(<TimerView appState={appState} />, document.body);

Step3:更改状态

使用 observable 来装饰状态和视图,就能让 Mobx 检测关系。

1
2
3
4
5
6
7
8
9
appState.resetTimer = action(function reset() {
appState.timer = 0;
});
setInterval(
action(function tick() {
appState.timer += 1;
}),
1000
);

深入了解核心概念

State(状态)

State 是驱动应用的数据。通常可分为领域特定状态和视图状态。

Derivations(衍生)

任何源自状态并且不会再有任何进一步的相互作用的东西就是 Derivations。

Derivations 以多种形式存在:

  • 用户界面
  • 衍生数据,比如剩下的待办事项的数量。
  • 后端集成,比如把变化发送到服务器端。

MobX 区分了两种类型的衍生:

  • Computed values(计算值) - 它们是永远可以使用纯函数(pure function)从当前可观察状态中衍生出的值。
  • Reactions(反应) - Reactions 是当状态改变时需要自动发生的副作用。需要有一个桥梁来连接命令式编程(imperative programming)和响应式编程(reactive programming)。或者说得更明确一些,它们最终都需要实现 IO 操作。

如果想创建一个基于当前状态的值时,请使用 computed。

Actions(动作)

Action 是任一一段可以改变状态的代码。

如果是在严格模式下使用 MobX 的话,MobX 会强制只有在动作之中才可以修改状态。

原则

MobX 支持单向数据流,也就是动作改变状态,而状态的改变会更新所有受影响的视图。

Action->State->Views

  • 当状态改变时,所有衍生都会进行原子级的自动更新。因此永远不可能观察到中间值。
  • 所有衍生默认都是同步更新。这意味着例如动作可以在改变状态之后直接可以安全地检查计算值。
  • 计算值是延迟更新的。任何不在使用状态的计算值将不会更新,直到需要它进行副作用(IO)操作时。如果视图不再使用,那么它会自动被垃圾回收。
  • 所有的计算值都应该是纯净的,它们不应该用来改变状态。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {observable, autorun} from 'mobx';
var todoStore = observable({
/* 一些观察的状态 */
todos: [],
/* 推导值 */
get completedCount() {
return this.todos.filter(todo => todo.completed).length;
}
});
/* 观察状态改变的函数 */
autorun(function() {
console.log("Completed %d of %d items",
todoStore.completedCount,
todoStore.todos.length
);
});
/* ..以及一些改变状态的动作 */
todoStore.todos[0] = {
title: "Take a walk",
completed: false
};
// -> 同步打印 'Completed 0 of 1 items'
todoStore.todos[0].completed = true;
// -> 同步打印 'Completed 1 of 1 items'