MobX是一个简单有效的状态管理库,以派生(derive)的概念为核心,以观察者模式为手段,达到了修改数据自动更新界面等目的
- 正因为其本身提供了包装react的方法,可以简洁的改善react组件,所以官网文档和几乎所有教程都以react和ES7的装饰修饰符等特性为切入点
- 但MobX在传统的ES5环境中也能良好工作,本文尝试以此为出发点,探讨在既有的非react项目中直接引入MobX并用其整理重构老代码的方法
没有babel、webpack、JSX...那么多的套路!直接上手先,走你~
[IV]. 常用工具方法
4.1 autorunAsync
- 语法:
autorunAsync(fn: () => void, minimumDelay?: number, scope?)
- 和立即执行的autorun不同的是,该方法延迟minimumDelay毫秒才执行
- 如果被观察对象在延迟期内多次改变,该方法也仅执行一次,这种情况下的效果就类似runInAction了
- 适合于那些不需要经常执行,或代价较大的操作
- 如果指定了scope参数,则fn会被绑定到scope上
4.2 Atom
代码语言:javascript复制符合Atom类规则的实例,可以在数据变化时通知MobX,或者接受MobX该对象是否被观察的通知以做出响应
class Clock {
atom;
intervalHandler = null;
currentDateTime; constructor() {
this.atom = new Atom( //创建一个与MobX交互的Atom实例
"Clock", //调试用的名字
() => this.startTicking(), //可选,变为可观察时被调用
() => this.stopTicking() //可选,变为不可观察时调用
);
} getTime() {
if (this.atom.reportObserved()) { //被观察时
return this.currentDateTime;
} else {
return new Date();
}
} tick() {
this.currentDateTime = new Date();
this.atom.reportChanged(); //通知MobX
} startTicking() {
this.tick(); // 初始化 tick
this.intervalHandler = setInterval(
() => this.tick(),
1000
);
} stopTicking() {
clearInterval(this.intervalHandler);
this.intervalHandler = null;
}
}const clock = new Clock();const disposer = autorun(() => console.log(clock.getTime()));// ...每秒钟都会打印出时间disposer();// 停止打印
4.3 expr
代码语言:javascript复制
expr()
创建一个reaction中临时的派生值,使得只在满足其返回值条件时,reaction才执行,从而避免不必要的响应
var obj = mobx.observable({a:1, b:2});var act = mobx.action(function(){
setTimeout(function(){
console.log('[after 1s]');
mobx.runInAction(function(){
obj.a = 3;
obj.b = 4;
});
}, 1000);
});act();mobx.autorun(function() {
var is5 = obj.a === 5;
console.log('reaction#2 is running...');
if (is5) console.log('a is 5 now');
});mobx.autorun(function() {
var is5 = mobx.expr(()=>obj.a === 5); //仅在初始化和a等于5时响应
console.log('reaction#3 is running...');
if (is5) console.log('a is 5 now');
});/* 输出:
1 2
reaction#2 is running...
reaction#3 is running...
[after 1s]
reaction#2 is running...
3 4
*/
4.4 isObservable
- 语法:
isObservable(obj, propertyName?)
- 类似的方法有 isObservableMap, isObservableArray, isObservableObject
var person = mobx.observable({
firstName: "Sherlock",
lastName: "Holmes"
});person.age = 3;mobx.isObservable(person); // true
mobx.isObservable(person, "firstName"); // true
mobx.isObservable(person.firstName); // false
mobx.isObservable(person, "age"); // false
4.5 reaction()
一个autorun的变种,提供更细粒度的控制,精确指定跟踪哪些被观察对象
语法: reaction( () => data, data => { sideEffect }, options? )
- 该方法头两个参数是两个函数,头一个data函数跟踪并返回用到的数据;返回值传递给第二个产生副作用的effect函数做参数
- 和autorun不同的是,effect函数在创建时并不立即生效,而是在第一次得到新的值后生效
- reaction()返回值是一个解除观察的函数
- 第三个参数options包含以下选项
context
指定this的指向fireImmediately
首次接收数据时是否触发,默认为falsedelay
延迟毫秒数compareStructural
默认为false; 如果为true,则每次比较data函数返回值的结构,和上一次不一样才调用effect函数name
调试用的名字
const todos = mobx.observable([
{
title: "Make coffee",
done: true,
},
{
title: "Find biscuit",
done: false
}
]);//错误的用法:如果数组长度不变化,就得不到响应
const reaction1 = mobx.reaction(
() => todos.length,
length => console.log("reaction 1:", todos.map(todo => todo.title).join(", "))
);//数组长度改变、数组项title改变都会响应
const reaction2 = mobx.reaction(
() => todos.map(todo => todo.title),
titles => console.log("reaction 2:", titles.join(", "))
);//每次都响应
const autorun1 = mobx.autorun(
() => console.log("autorun 1:", todos.map(todo => todo.title).join(", "))
);todos.push({ title: "explain reactions", done: false }); //3个reaction都响应
todos[0].title = "Make tea"; //reaction1无法响应
4.6 toJS
用法: toJS(value, supportCycles = true)
- 递归的将可观察对象转换成原生js结构
- 支持的可观察对象包括:数组、对象、map和基本类型
- 派生值和其他不可枚举的属性不会包含在结果中
- 第二个参数设为false可以浅转换以提高性能
var obj = mobx.observable({
x: 1
});var clone = mobx.toJS(obj);console.log(mobx.isObservableObject(obj)); // true
console.log(mobx.isObservableObject(clone)); // false
4.7 untracked
使某段代码不被观察
代码语言:javascript复制const person = mobx.observable({
firstName: "Michel",
lastName: "Weststrate"
});mobx.autorun(() => { //并不依赖firstName
console.log(
person.lastName,
",",
untracked(() => person.firstName)
);
});
// prints: Weststrate, Michelperson.firstName = "G.K.";
// 不打印person.lastName = "Chesterton";
// prints: Chesterton, G.K.
4.8 when
用法: when(debugName?, predicate: () => boolean, effect: () => void, scope?)
function Car() {
mobx.extendObservable(this, {
speed: 60,
state: 'running',
setState: mobx.action(function(state) {
this.state = state;
})
});
mobx.when(
function once() { return this.state === 'stop'; }.bind(this),
function then() { console.log('STOP!'); this.speed = 0; }.bind(this)
);
}var car = new Car;mobx.autorun(function(){
console.log('car speed: ', car.speed);
});setTimeout(function(){
car.setState('stop');
}, 500);/* 输出:
car speed: 60
STOP!
car speed: 0
*/
* 原创文章转载请注明出处