MobX是一个简单有效的状态管理库,以派生(derive)的概念为核心,以观察者模式为手段,达到了修改数据自动更新界面等目的
- 正因为其本身提供了包装react的方法,可以简洁的改善react组件,所以官网文档和几乎所有教程都以react和ES7的装饰修饰符等特性为切入点
- 但MobX在传统的ES5环境中也能良好工作,本文尝试以此为出发点,探讨在既有的非react项目中直接引入MobX并用其整理重构老代码的方法
没有babel、webpack、JSX...那么多的套路!直接上手先,走你~
[III]. 常用API
3.1 computed
computed values
指的是从状态或其他派生值中派生出来的值
- 当依赖的值改变时,派生值也自动更新
- 产生派生值的函数应该是无副作用的纯函数
除了上面提过的在类实例里使用 getter/setter 和 computed(), computed(expression)
也可以直接用来当作一个独立的函数:
var name = mobx.observable("John");var upperCaseName = mobx.computed(() =>
name.get().toUpperCase()
);var disposer = upperCaseName.observe(
change => console.log(change.newValue)
);name.set("Dave");
// prints: 'DAVE'
处理派生函数中的错误:
应注意正确的报错方式是 throw new Error("err")
,而非throw "err"
或其他
const x = observable(3)
const y = observable(1)
const divided = computed(() => {
if (y.get() === 0)
throw new Error("被除数是0")
return x.get() / y.get()
})divided.get() // returns 3y.set(0) // OK
divided.get() // 报错,此次set失败y.set(2)
divided.get() // 恢复并 Returns 1.5
3.2 autorun
autorun(debugName?, fn)
被用来对那些没有单独设置观察者的状态创建reaction函数
- 当初始化和依赖的值改变时,相关的函数就会执行
- autorun的返回值是一个解除观察的函数
var str = mobx.observable('are you ok');
str.observe(change=>console.log(change.oldValue, '->', change.newValue));
mobx.autorun(()=>console.log('AAA', str.get()));
str.set('i am fine!');/* 输出:
AAA are you ok
AAA i am fine!
are you ok -> i am fine!
*/
代码语言:javascript复制var numbers = mobx.observable([1,2,3]);
var sum = mobx.computed(() => numbers.reduce((a, b) => a b, 0));var disposer = mobx.autorun(() => console.log(sum.get())); // prints '6'numbers.push(4); // prints '10'
disposer();
numbers.push(5); // 无输出
autorun中的错误处理:
代码语言:javascript复制const age = mobx.observable(10);
const dispose = mobx.autorun(() => {
if (age.get() < 0)
throw new Error("年龄不能为负数")
console.log("Age", age.get())
});mobx.extras.onReactionError(
(error, derivation)=>console.warn('global err handler: ', error)
);age.set(18); // Logs: Age 18
age.set(-10); // 报错, 但会在全局err处理中被
age.set(5); // Recovered, logs Age 5dispose.onError(err=>console.warn(err));age.set(-5); // 不报错,被onError拦截
3.3 action
- 用
action(debugName?, fn)
语法,创建一个action,用来改变状态 - action可以用于任何改变可观察状态的方法,或有副作用的方法
- 对于派生属性对应的setter方法,将自动被视为一个action
- 设置
mobx.useStrict(true)
,就可以严格限定对状态的改变只能在action中进行 - action中的fn会被包装上
mobx.untracked()
、mobx.transaction()
和mobx.extras.allowStateChanges()
几个方法,从而使该action达到不被追踪、允许并集中修改状态的目的 - 如果使用
action.bound(fn)
替换action(fn)
,则fn和目标对象绑定,this
指向一直都不会变
action中的异步动作:
- action仅对其包裹的fn生效,而由fn调度的函数则不会有效果
- 对于一些异步方法,比如setTimeout,promise或async/await,可以将需要异步处理的部分写进
runInAction(name?, fn, scope?)
- runInAction也被用来替换过时的transaction,批量执行多个状态变更,以免触发多次事件
var obj = mobx.observable({a:1, b:2});var act = mobx.action(function(){
setTimeout(function(){
mobx.runInAction(function(){
obj.a = 3;
obj.b = 4;
});
}, 1000);
});act();mobx.autorun(function(){
console.log(obj.a, obj.b);
});/* 输出:
1 2
3 4
*/