Appearance
mobx
mobx是一个简单可扩展的状态管理库,相比较于redux,它:
开发难度低
开发代码量少
渲染性能好

浏览器兼容性
MobX >=5 版本运行在任何支持 ES6 proxy 的浏览器。 MobX 4 可以运行在任何支持 ES5 的浏览器上,而且也将进行持续地维护。MobX 4 和 5 的 API 是相同的,并且语义上也能达到相同的效果。 MobX 6 「最新版本」移除了装饰器的操作(因为装饰器不是JS标准规范)!
想要使用mobx,首先需要让项目支持JS装饰器语法!
bash
yarn add @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties
1
package.json
json
"babel": {
"presets": [ "react-app" ],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
/* legacy /ˈleɡəsi/:使用历史遗留(Stage-1)的装饰器中的语法和行为。它为提案从 Stage-1 到当前阶段 Stage-2 平稳过渡作铺垫*/
"legacy": true
}
],
[
"@babel/plugin-proposal-class-properties",
{
/* loose=false时,是使用Object.defineProperty定义属性,loose=ture,则使用赋值法直接定义 */
"loose": true
}
]
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mobx 第五代版本的运用
bash
yarn add mobx@5 mobx-react@6
1
初窥mobx
实现一个简单的计数器累加效果
JavaScript
import { observable, action } from 'mobx';
import { observer } from 'mobx-react';
// 公共状态管理
class Store {
@observable num = 10;
@action handle() {
this.num++;
}
}
const store = new Store;
//组件监听
@observer
class Demo extends React.Component {
render() {
return <div>
<span>{store.num}</span>
<br />
<button onClick={() => {
store.handle();
}}>按钮</button>
</div>;
}
}
// 函数组件不支持装饰器,我们则基于observer把其执行即可
/* const Demo = observer(function Demo() {
return <div>
...
</div>;
}); */
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Demo />
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
observable
一个实现“监听值变化”的函数或者装饰器! 先来看一个效果
JavaScript
import { observable, autorun } from 'mobx';
class Store {
// 只有基于 observable 装饰器修饰的属性,在可以在修改其值后,监测到它的变化
@observable x = 10;
}
let store = new Store;
// 监听用到的依赖,当依赖改变时会执行callback「最开始立即执行一次」
autorun(() => {
console.log('autorun:', store.x);
});
// 一秒钟后改变内容
setTimeout(() => {
store.x = 100;
}, 1000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
探索 observable 的原理
JavaScript
import { observable, observe } from 'mobx';
let obj = observable({
x: 10,
y: 20
});
// console.log(obj); //对象是经过ES6 Proxy做了劫持处理的
// observe:当监听的对象做出变化时,触发callback
observe(obj, change => {
console.log('内容改变了:', change);
});
obj.x = 100;
//----
// observable不能直接对原始值类型进行监听,需要基于.box处理
let x = observable.box(10);
observe(x, change => {
console.log('内容改变了:', change);
});
console.log(x, x.get());
x.set(1000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
所以我们以后创建的公共状态信息,前面都要设置 @observable 装饰器!!
computed计算属性
JavaScript
import { observable, autorun, computed, reaction } from 'mobx';
class Store {
@observable x = 10;
@observable count = 3;
@observable price = 120;
// 设置具备计算缓存的计算属性:依赖的状态值没有变化,方法不会重新执行,使用之前计算缓存的结果
@computed get total() {
console.log('OK');
return this.count * this.price;
}
}
let store = new Store;
autorun(() => {
console.log('autorun:', store.total, store.x);
});
// 相比较于autorun,提供更精细的管控「第一次不会触发」
reaction(
() => [store.total, store.x],
() => {
console.log('reaction:', store.total, store.x);
}
);
setTimeout(() => {
store.x = 1000;
store.count = 10;
}, 1000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
action修改公共状态的方法
JavaScript
import { observable, autorun, action, configure } from 'mobx';
// 设定只能基于action方法修改状态值
configure({
enforceActions: "observed"
});
class Store {
@observable x = 10;
@action changeX(val) {
this.x = val;
}
}
let store = new Store;
autorun(() => {
console.log('autorun:', store.x);
});
setTimeout(() => {
store.changeX(1000);
// store.x = 2000; //Uncaught Error: [mobx] Since strict-mode is enabled, changing observed observable values outside actions is not allowed.
}, 1000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
JavaScript
class Store {
@observable x = 10;
// .bound确保this永远是实例
@action.bound changeX(val) {
this.x = val;
}
}
let store = new Store;
...
setTimeout(() => {
let changeX = store.changeX;
changeX(1000);
}, 1000);
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
JavaScript
class Store {
@observable x = 10;
}
let store = new Store;
autorun(() => {
console.log('autorun:', store.x);
});
setTimeout(() => {
// 基于runInAction代替action修饰器「即便设置enforceActions配置项,它也是被允许的」,和action修饰器具备相同的效果!!
runInAction(() => {
store.x = 1000;
});
}, 1000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
实现异步派发
JavaScript
// 模拟从服务器获取数据
const query = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve(1000);
}, 1000);
});
};
class Store {
@observable x = 10
@action.bound async changeX() {
let res = 0;
try {
res = await query();
} catch (_) { }
this.x = res;
}
}
let store = new Store;
autorun(() => {
console.log('autorun:', store.x);
});
store.changeX();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24