用MobX管理状态(ES5实例描述)-4.常用工具方法

2020-06-15 15:00:39 浏览数 (1)

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

符合Atom类规则的实例,可以在数据变化时通知MobX,或者接受MobX该对象是否被观察的通知以做出响应

代码语言:javascript复制
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

expr()创建一个reaction中临时的派生值,使得只在满足其返回值条件时,reaction才执行,从而避免不必要的响应

代码语言:javascript复制
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
代码语言:javascript复制
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 首次接收数据时是否触发,默认为false
    • delay 延迟毫秒数
    • compareStructural 默认为false; 如果为true,则每次比较data函数返回值的结构,和上一次不一样才调用effect函数
    • name 调试用的名字
代码语言:javascript复制
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可以浅转换以提高性能
代码语言:javascript复制
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?)

代码语言:javascript复制
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
*/

* 原创文章转载请注明出处

0 人点赞