前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用MobX管理状态(ES5实例描述)-2.可观察的类型

用MobX管理状态(ES5实例描述)-2.可观察的类型

作者头像
江米小枣
发布2020-06-15 14:59:57
6240
发布2020-06-15 14:59:57
举报
文章被收录于专栏:云前端云前端云前端

MobX是一个简单有效的状态管理库,以派生(derive)的概念为核心,以观察者模式为手段,达到了修改数据自动更新界面等目的

  • 正因为其本身提供了包装react的方法,可以简洁的改善react组件,所以官网文档和几乎所有教程都以react和ES7的装饰修饰符等特性为切入点
  • 但MobX在传统的ES5环境中也能良好工作,本文尝试以此为出发点,探讨在既有的非react项目中直接引入MobX并用其整理重构老代码的方法

没有babel、webpack、JSX...那么多的套路!直接上手先,走你~

[II]. 可观察的类型

语法 mobx.observable(value)

2.1 普通对象

  • 普通对象指不是通过构造函数创建的,没有特定原型对象的 plain object
  • 如果一个普通对象被传递到 observable() 中,其所有属性都会成为可观察的,并被拷贝到一个副本中(对副本的更改也同时影响原始对象的值)
  • 默认是递归处理的,如果一个属性是对象或数组,其元素也会被观察
var $ctn = document.querySelector('#container');var obj = {
   a: 1,
   b: {
       c: 3,
       d: 4
   }
};var observ = mobx.observable(obj);
   
setTimeout(function(){
   observ.b.c = 666;
}, 1000);mobx.autorun(function(){
   //元素内容变为 [new value] c: 666
   $ctn.innerHTML = "[new value] c: " + observ.b.c;
});setTimeout(function(){
   alert([obj.b.c, observ.b.c]; //666, 666
}, 2000);
浅观察:

observable.shallowObject(value)方法可以实现“浅观察”,只自动响应“浅层”的子属性

var $ctn1 = document.querySelector('#container1');
var $ctn2 = document.querySelector('#container2');
var $info = document.querySelector('#info');var obj = {
   a: 1,
   b: {
       c: 3,
       d: 4
   }
};var observ1 = mobx.observable.shallowObject(obj);
var observ2 = mobx.observable.shallowObject(obj);mobx.autorun(function(){
   //元素内容变为 [new value of observ1] c: 3
   $ctn1.innerHTML = "[new value of observ1] c: " + observ1.b.c;
});
mobx.autorun(function(){
   //元素内容变为 [new value of observ2] c: 999, a: 555
   $ctn2.innerHTML = "[new value of observ2] c: " + observ2.b.c + ", a: " + observ2.a;
});setTimeout(function(){
   observ1.b.c = 666;
   observ2.b.c = 999;
   observ2.a = 555;
}, 1000);
setTimeout(function(){
   $info.innerHTML = [obj.b.c, observ1.b.c, observ2.b.c].join(','); //999, 999, 999
}, 2000);

2.2 数组

  • 和对象类似的是,向observable()传递一个数组参数,数组中的每一项也会变为可观察的,且默认为递归处理的深度观察
  • 和对象类似,数组也有一个浅观察的方法 observable.shallowArray(value)
  • Array.isArray(observable([]))会返回fasle,但可用Array.isArray(observable([]).slice())达到正确的效果
  • 与原生数组对象的sort()reverse()方法不同的是,可观察数组的这两个方法返回相应结果的一个数组副本,而不影响原数组
  • 除了内建的数组方法,可观察数组也扩展了如下方法:
    • clear()
    • replace(newItems)
    • find(predicate: (item, index, array) => boolean, thisArg?, fromIndex?)
    • remove(value)
    • peek(): 和slice()类似,返回一个安全的原生数组
    • intercept(change=> change|null ): 拦截更改,并可指定使用自定义后的更改
    • observe(change=>{}, fireImmediately? = false): 监听更改
var todos = observable([
   { title: "Spoil tea", completed: true },
   { title: "Make coffee", completed: false }
]);autorun(() => {
   console.log("Remaining:", todos
       .filter(todo => !todo.completed)
       .map(todo => todo.title)
       .join(", ")
   );
});
// Prints: 'Remaining: Make coffee'todos[0].completed = false;
// Prints: 'Remaining: Spoil tea, Make coffee'todos[2] = { title: 'Take a nap', completed: false };
// Prints: 'Remaining: Spoil tea, Make coffee, Take a nap'todos.shift();
// Prints: 'Remaining: Make coffee, Take a nap'

2.3 Map

  • observable.map(values?) 可以创建一个可观察的Map类型
  • 可选的一个参数,可以是一个对象、一个ES6 Map,或是一个键值字符串数组
  • 类似于对象,可以用observable.shallowMap(values)实现浅观察
var a = mobx.observable.map({a:111})
console.log('map1 ', a.get('a')); //111var es6Map = new Map();
es6Map.set('a', 222);
var b = mobx.observable.map(es6Map);
console.log('map2', b.get('a')); //222var c = mobx.observable.map(['a', 'b', 'c']);
console.log(c.toJS()); //{a: undefined, b: undefined, c: undefined}

和ES6规范中相同的方法包括:

  • has(key)
  • set(key, value)
  • delete(key)
  • get(key)
  • keys()
  • values()
  • entries()
  • forEach(callback:(value, key, map) => void, thisArg?)
  • clear()
  • size

不同于ES6规范的方法包括:

  • toJS() - 得到一个浅复制的javascript对象( 深复制用mobx.toJS(map) )
  • merge(values) - 合并新的对象到Map中,参数格式同初始化方法
  • replace(values) - 替换,相当于 map.clear().merge(values)
  • intercept(interceptor)
  • observe(listener, fireImmediately?)

2.4 基本类型值和引用

  • 所有JS的基本值都是不可变的,因此单个变量无法被观察
  • MobX将这些类型转换成可观察的“boxed value”

转换后的对象可调用如下方法:

  • get() - 取得当前值
  • set(value) - 替换当前值,并通知所有观察者方法
  • intercept(interceptor)
  • observe(callback: (change) => void, fireImmediately = false)
const cityName = observable("Vienna");console.log(cityName.get());
// prints 'Vienna'cityName.observe(function(change) {
   console.log(change.oldValue, "->", change.newValue);
});cityName.set("Amsterdam");
// prints 'Vienna -> Amsterdam'
浅观察
  • observable.shallowBox(value)基于observable.ref()实现了浅观察
  • 这意味着只观察引用本身,而其值并不会被自动观察
var str2 = "world";
var pobj2 = mobx.observable(str2);var str3 = "!!!";
var pobj3 = mobx.observable.shallowBox(str3);mobx.autorun(function(){
   console.log(str2, pobj2.get());
   console.log(str3, pobj3.get());
});setTimeout(function() {
   console.log('[after 1s]');
   mobx.runInAction(()=>{
       pobj2.set("wo____rld");
       pobj3.set("~~~");
   });
}, 1000);setTimeout(function() {
   console.log('[after 2s]');
   mobx.runInAction(()=>{
       pobj2.set({a: 11});
       pobj3.set({b: 22});
   });
}, 2000);/* autorun输出:world world
!!! !!![after 1s]
world wo____rld
!!! ~~~[after 2s]
world {$mobx: ObservableObjectAdministration}
!!! {b: 22}
*/

2.5 类实例

对于类实例,需要在构造函数中或对实例对象调用mobx.extendObservable(targetName, ...props)方法:

var Person = function(firstName, lastName) {
   //不需要观察的实例属性
   this.id = (new Date).getTime();
   //需要观察的实例属性
   mobx.extendObservable(this, {
       firstName: firstName,
       lastName: lastName
   });
}var matthew = new Person("Matthew", "Henry");//对已初始化的实例增添新的可观察属性
mobx.extendObservable(matthew, {
   age: 25
});
类实例中的描述符
  • 描述符被用来对指定的属性定义特殊的行为
  • 比如用observable.ref()来浅观察引用、用computed()来声明一个派生属性,或用action()定义一个改变状态的动作
var Person2 = function(firstName, lastName) {
   this.id = (new Date).getTime();
   mobx.extendObservable(this, {
       firstName: mobx.observable.ref(firstName),
       lastName: mobx.observable.ref(lastName),
       fullName: mobx.computed(function() {
           return this.firstName + " " + this.lastName
       }),
       setLastName: mobx.action(function(name) {
           this.lastName = name;  
       })
   });
};var p2 = new Person2('tom', 'jerry');
p2.setLastName('trump');
p2.firstName = 'donald';
console.log(p2.fullName); //用computed定义的派生属性用法上类似getter
类实例中的 getter/setter
  • 也可以用getter定义一个派生属性
  • 配对的setter是可选的,用来定义一个action; 且该方法不能直接操作派生属性,而是通过改变核心状态影响它
var Person3 = function(firstName, lastName) {
   this.id = (new Date).getTime();
   mobx.extendObservable(this, {
       firstName: firstName,
       lastName: lastName,
       get fullName() {
           return this.firstName + " " + this.lastName
       },
       set fullName(newValue) {
           var parts = newValue.split(" ")
           this.firstName = parts[0]
           this.lastName = parts[1]
       }
   });
};var p3 = new Person3;
p3.fullName = "ivanka trump";
console.log(p3.fullName, p3.firstName);
类实例中的浅观察
  • extendShallowObservable(value)同样基于observable.ref()实现了浅观察
  • observable.deep(prop)被用来对某个属性单独指定深观察
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-03-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • [II]. 可观察的类型
    • 2.1 普通对象
      • 浅观察:
    • 2.2 数组
      • 2.3 Map
        • 2.4 基本类型值和引用
          • 浅观察
        • 2.5 类实例
          • 类实例中的描述符
          • 类实例中的 getter/setter
          • 类实例中的浅观察
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档