MobX 是状态管理库(侵入性最小之一),用来管理应用的内部状态。但是请注意,MobX 和 Redux 不同,只是一个解决技术问题的库,而不是状态管理容器。
MobX 通过透明的函数响应式编程使得状态管理变得简单和可扩展。
- 灵感:来自excel表格中的反应式编程原理
- 哲学:任何源自应用状态的东西都应该自动地获得。
- 易操作性:相比其它状态管理解决方案,当使用 MobX 时通常只需学习更少的新概念。
在 MobX 中使用装饰器有两种方式:
- 使用装饰器语法(需确保在 Babel 里配置了)
- 利用 MobX 内置的工具 decorate 来对类和对象进行装饰
下面代码使用装饰器语法进行。(完整示例)
定义State
observable 值可以是JS基本数据类型、引用类型、普通对象、类实例、数组和映射。(普通对象是指不是使用构造函数创建出来的对象,而是以 Object 作为其原型,或者根本没有原型)
import {observable, computed} from "mobx";
class ChestnutStore {
@observable chestnuts = [];
@computed get total() {
return this.chestnuts.length;
}
}
反应 是自动响应状态变化的副作用。 反应可以确保当相关状态发生变化时指定的副作用(主要是 I/O)可以自动地执行,比如打印日志、网络请求 等等
- 使用 @observable 装饰器来给类属性添加注解,就可以简单的为数据结构添加了可观察的功能。
MobX 不会将一个有原型的对象自动转换成 observable,因为这是构造函数的职责。
对于非普通对象,构造函数负责初始化 observable 属性,在构造函数中使用 extendObservable 或在类定义上使用 @observable / decorate 。
- 通过 @computed 装饰器可以定义在相关数据发生变化时自动更新的值。(自动响应状态变化的值)
计算值有助于使实际可修改的状态尽可能的小。( 此外计算值还是高度优化过的,所以尽可能的多使用它们)
注意计算属性是不可枚举的,它们也不能在继承链中被覆盖。
创建视图以响应状态的变化
import React from "react";
import ReactDOM from "react-dom";
import { observer } from "mobx-react";
import { observable, computed, autorun, when, reaction } from "mobx";
const store = new ChestnutStore();
@observer
class Chestnut extends React.Component {
constructor(props) {
super(props);
this.stop = autorun(() => console.log(store.total));
when(() => store.chestnuts.length > 10, () => alert("数量大于10了"));
reaction(
() => store.chestnuts.map(item => item),
items => console.log(items.join(","))
);
}
render() {
return (
<div>
<ul>{store.chestnuts.map(item => item)}</ul>
<p> Total: {store.total}</p>
<button
type="button"
onClick={() => store.chestnuts.push(store.chestnuts.length)}
>
add
</button>
<button type="button" onClick={() => store.chestnuts.pop()}>
remove
</button>
<button type="button" onClick={() => this.stop()}>
终止autorun
</button>
</div>
);
}
}
- observer 函数/装饰器可以用来将 React 组件转变成响应式组件。
它用 mobx.autorun 包装了组件的 render 函数以确保任何组件渲染中使用的数据变化时都可以强制刷新组件
- autorun 用来创建一个响应式函数,而该函数本身永远不会有观察者
使用 autorun 时,所提供的函数总是立即被触发一次,然后每次它的依赖关系改变时会再次被触发。(autorun 只会观察函数运行时访问过的 observable 的状态)
如果你有一个函数应该自动运行,但不会产生一个新的值,请使用autorun。
autorun 返回一个清理函数用来取消副作用。
- when 观察并运行给定的函数,直到返回值为 true。(一旦返回 true,给定的 effect 就会被执行,然后自动运行程序会被清理,也就是只会执行一次 effect 函数)
如果没提供 effect 函数,when 会返回一个 Promise 。它与 async / await 可以完美结合。
- reaction 对于如何追踪 observable 赋予了更细粒度的控制。
它接收两个函数参数:
- 第一个数据函数是用来追踪并返回数据,作为第二个副作用函数的输入。
- 第二个副作用函数被调用时会接收两个参数。 第一个参数是由 数据函数 返回的值。 第二个参数是当前的 reaction,可以用来在执行期间清理 reaction。(副作用函数只有在数据函数返回的数据发生更改后才会运行)
reaction 也返回一个清理函数。不同于 autorun 的部分是,当创建函数时不会立即触发一次。
更改状态
除了上面代码中直接修改状态。MobX 也可以使你在代码中显式地标记出动作所在的位置。
@action
method() {
//...一些逻辑
}
action.bound 可以用来自动地将动作绑定到目标对象,但不要和箭头函数一起使用,箭头函数已经是绑定过的并且不能重新绑定。
开启“严格模式”,需要强制使用 action,不允许在 action 外更改任何状态
configure({ enforceActions: "observed" })
注意点:
- MobX 追踪属性访问,而不是值。例:
如果你在 autorun 中的依赖是引用类型,而不是引用类型中某个具体属性,那么直接修改其中的数据,并不会触发 autorun 。
一些解决方案:
- 可以通过 mobx.toJS() 创建深克隆
- ... 创建浅克隆
- JSON.stringify()读取整个结构
- 在大型、长期的项目中,若随意的变更数据会使程序状态无法追踪,不可预测。所以建议开启 MobX 的严格模式,再加上一套状态管理的规范,让出错的可能性和找问题的成本降到最低,更方便项目的质量管理。(或者改用 redux 吧)
参考链接:
MobX中文文档
网友评论