1 可观察的数据(observable)

observable是一种让数据的变化可以被观察的方法。

那些数据可被观察?

-原始类型

String、Number、Boolean、Symbol

-对象

-数组

代码中理解数据是如何被观察的:

1)安装mobx的npm依赖

执行命令:npm i mobx -S

2)在index.js文件中,从mobx包中导入observable函数

import { observable } from 'mobx';

3)通过observable将变量转换为可观察的对象

mobx对任意变量对处理方式有两种:

 -数组、对象以及es6中的map

  直接把observable作为函数来将变量转换为可观察对对象,之后对数组、以及map中的数据进行合理的操作。

  >数组(array) 

import { observable,isArrayLike } from 'mobx';
// import { observable } from 'mobx';
const arr = observable(['a','b','c']);
console.log(arr[0],arr.push('d'));
//如果直接用observable函数返回的结果不是数组,而引入isArrayLike模块后,返回的就相当于数组,
//可以用一些数组的方法,但注意不能通过数组越界的方式访问或改变数组数据,mobx不会监视越界的访问  

  >对象(object)

import { observable } from 'mobx';
const obj = observable({a:1,b:1});
console.log(obj.a,obj.b);
//mobx只能对已有的数据进行监视,如果要监视新增加的属性,需要使用mobx提供的extendObservable()方法。
//因此最好在程序初始化的时候就说明所有程序会用到的属性。

  >map

import { observable } from 'mobx';
const map = observable(new Map());
map.set('a',1);
console.log(map.has('a'));
map.delete('a');
console.log(map.has('a'));
//和数组类型的类似,返回的结果不是真正的map,但表现的足够接近map,可以调用一些map的方法

 -其他类型

  一些原始类型数据,如String、Number、Boolean等,需要调用observable.box来将变量包装为可观察的对象,之后对该变量的直接赋值将会被监视。

import { observable } from 'mobx';
const num = observable.box(20);
const str = observable.box('Hello');
const bool = observable.box(true);
// console.log(num,str,bool); //返回的是包装好的可被观察到数据
console.log(num.get(),str.get(),bool.get());
num.set(1);
str.set('hi~');
bool.set(false);
console.log(num.get(),str.get(),bool.get());
//使用get方法得到原始类型的值,使用set方法修改原始类型的值

4)使用decorator修饰器声明可观察对象

decorator只能修饰类或类的成员,因此我们要创建一个类,在该类中使用observable创建可被观察的数据。

mobx为了简化api对observable函数做了手脚,使其能够识别函数当前是被当作普通函数调用还是被当作修饰器调用的,如果是作为修饰器被调用,就自动识别变量类型,并使用不同的包装转换方案。

import { observable,isArrayLike } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false;
}

2 对可观察对数据做出反应(如何知道对象被修改了?)

观察数据变化的方式共四种:computed、autorun、when和Reaction。

computed(可以将多个可观察数据组合成一个新的可观察数据。)

计算值,它将其他可观察数据以我们想要的方式组合起来变成一个新的可观察数据。

有两种使用方法:作为普通函数和作为修饰器。

首先从mobx中引入computed

1)作为普通函数

1⃣️得到数据的计算值:

import { observable,isArrayLike,computed } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false;
} var store = new Store();
var foo = computed(function(){ return store.string + '/' + store.number });
// console.log(foo);//ComputedValue对象
//可以使用get方法来获取这个计算值的最终值
console.log(foo.get()); //Hello/20

打印foo的结果:

打印get函数返回的计算结果:

2⃣️监视数据的变化

为了能够监视数据的变化,需要在返回的ComputedValue对象上调用observe方法。

import { observable,isArrayLike,computed } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false;
} var store = new Store(); var foo = computed(function(){ return store.string + '/' + store.number }); foo.observe(function(change){
console.log(change);
})
store.string = 'world';
store.number = 30;

输出结果:

2)作为修饰器

computed更多是作为decorator修饰器来修饰类的get属性成员的。

import { observable,isArrayLike,computed } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false; @computed get mixed() {
return store.string + '/' + store.number;
}
} var store = new Store();
console.log(store.mixed);//Hello/20

  

在作为修饰器的情况下,不能再调用observe方法了,通过store.mixed只能获得最终的计算值,这时就要用到另一种方法——autorun

autorun(可以自动追踪引用的可观察数据,并在数据发生变化时,重新触发)

在可观察数据发生改变之后,自动执行依赖可观察数据的行为,这个行为一般指的是传入autorun的函数。

1)自动运行什么:传入autorun的函数参数

首先从mobx中引入autorun

然后,创建一个autorun,并传入一个没有参数的函数。

同样会打印出计算结果,但不是自动运行的。

import { observable,isArrayLike,computed,autorun } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false; @computed get mixed() {
return store.string + '/' + store.number;
}
} var store = new Store(); autorun(() =>{
console.log(store.string + '/' + store.number);//Hello/20
});

  

2)怎么触发自动运行?

答:修改autorun中引用的任意可观察数据。

import { observable,isArrayLike,computed,autorun } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false; @computed get mixed() {
return store.string + '/' + store.number;
}
} var store = new Store(); autorun(() =>{
console.log(store.string + '/' + store.number);
}); store.string = 'world';
store.number = 30;

3)一些问题

1⃣️当项目中可观察数据较多的时候,数据每发生改变一次就触发一次autorun,会很浪费计算资源。

2⃣️computed值可以作为一种新的可观察数据看待。

autorun(() =>{
console.log(store.mixed);
});

上面修改后的代码和2)中结果一致。

computed值除了可以引用普通可观察数据外,还可以嵌套引用其他computed值,但不能有循环引用。

when(提供了执行逻辑的条件,算是一种改进后的autorun)

接收两个函数参数:

- 第一个函数:根据可观察数据返回一个布尔值。当该布尔值为true时,执行第二个函数,且只执行一次。

- 第二个函数:如果可观察数据返回的布尔值一开始就是true,那么立即同步执行第二个函数。

首先从mobx中引入when。

import { observable,isArrayLike,computed,autorun,when } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false; @computed get mixed() {
return store.string + '/' + store.number;
}
} var store = new Store(); when(() => store.bool,() => {console.log("it's true");});
store.bool = true;

无论是否修改了可观察数据,autorun都会先执行一次。

reaction(通过分离可观察数据声明,以副作用的方式,对autorun做出了改进)

单独告知mobx,我们引入了哪些可观察数据。

接收两个函数参数:

- 第一个函数:引用可观察数据,并返回一个值,这个值会作为第二个函数的参数。

- 第二个函数:也叫副作用函数。

首先从mobx中引入reaction。

import { observable,isArrayLike,computed,autorun,when,reaction } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false; @computed get mixed() {
return store.string + '/' + store.number;
}
} var store = new Store(); reaction(() => [store.string,store.number],arr => console.log(arr.join('/')));
store.string = 'world';
store.number = 30;

  

这样mobx就知道有哪些可观察数据被引用了,并在这些数据被修改后,执行第二个函数。

这样不必执行副作用,就可以建立副作用和可观察数据之间的联系。

在没有数据之前,没必要调用缓存逻辑,可以用reaction实现数据被第一次填充之后再来调用缓存逻辑。

3 修改可观察数据

上一节有一个问题:当项目中可观察数据较多的时候,数据每发生改变一次就触发一次autorun,会很浪费计算资源,在多数情况下,这种高频的触发是没必要的。

为了解决这个问题,mobx提出了action的概念,可以将多次对状态数据的赋值合并为一次,从而减少触发autorun或reaction的次数。

首先从mobx中引入action。

action也是既可以作为普通函数也可以作为decorator来使用,常用的是decorator的方式。

import { observable,isArrayLike,computed,autorun,when,reaction,action } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false; @computed get mixed() {
return store.string + '/' + store.number;
}
@action bar(){
this.string = 'world';
this.number = 30;
}
} var store = new Store(); reaction(() => [store.string,store.number],arr => console.log(arr.join('/'))); store.bar();

这样就只执行了一次reaction。

作为decorator,action还有一种变种——action.bound,相比与action多了把被修饰的方法的上下文强制绑定到该对象上。

import { observable,isArrayLike,computed,autorun,when,reaction,action } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false; @computed get mixed() {
return store.string + '/' + store.number;
}
@action.bound bar(){
this.string = 'world';
this.number = 30;
}
} var store = new Store(); reaction(() => [store.string,store.number],arr => console.log(arr.join('/'))); var bar = store.bar;
bar();

对代码修改后,对结果没有影响。这种方法在将方法作为callback传给其他镜像时特别有用。

它们两个都需要绑定在预先定义都对象方法上。

mobx还提供了一种语法糖,允许随时定义匿名的action方法,并运行它,这个API叫runInAction。

首先从mobx中引入runInAction,并创建runInAction,直接将对可观察数据修改的代码放到里面,结果和调用store.bar效果是一样的。

import { runInAction,observable,isArrayLike,computed,autorun,when,reaction,action } from 'mobx';

class Store {
@observable array = [];
@observable obj = {};
@observable map = new Map(); @observable string = 'Hello';
@observable number = 20;
@observable bool = false; @computed get mixed() {
return store.string + '/' + store.number;
}
@action.bound bar(){
this.string = 'world';
this.number = 30;
}
} var store = new Store(); reaction(() => [store.string,store.number],arr => console.log(arr.join('/'))); runInAction(() => {
store.string = 'world';
store.number = 30;
})

对于有多处重复调用的状态修改逻辑,建议用action来实现复用,否则用runInAction即可;

runInAction也可以接收字符串类型的参数:

runInAction('modify',() => {
store.string = 'world';
store.number = 30;
})  

使用action便于使用debug调试代码。

mobx学习笔记04——mobx常用api的更多相关文章

  1. Java基础学习笔记十四 常用API之基本类型包装类

    基本类型包装类 Java中有8种基本的数据类型,可是这些数据是基本数据,想对其进行复杂操作,变的很难.怎么办呢?在实际程序使用中,程序界面上用户输入的数据都是以字符串类型进行存储的.而程序开发中,我们 ...

  2. mobx学习笔记03——mobx基础语法(decorator修饰器)

    在声明阶段实现类与类成员注解的一种语法. function log(target){ const desc = Object.getOwnPropertyDescriotors(target.prot ...

  3. mobx学习笔记02——mobx基础语法(class)

    新的语法可能不被浏览器支持,可以使用babel转换为浏览器支持的代码格式: 为什么要定义class? js是一门面向对象的编程语言.需要利用类来复用代码,提高编程效率. 需要什么样的class能力? ...

  4. ASP.NET MVC Web API 学习笔记---第一个Web API程序

    http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html GetListAll /api/Contact GetListBySex ...

  5. 机器学习实战(Machine Learning in Action)学习笔记————04.朴素贝叶斯分类(bayes)

    机器学习实战(Machine Learning in Action)学习笔记————04.朴素贝叶斯分类(bayes) 关键字:朴素贝叶斯.python.源码解析作者:米仓山下时间:2018-10-2 ...

  6. docker学习笔记二:常用命令

    docker学习笔记二:常用命令 查看docker常用命令 docker --help 返回结果如下: 其中常用的命令如下: 1.image相关操作 展示所有的image: 删除image: rmi ...

  7. amazeui学习笔记--css(常用组件16)--文章页Article

    amazeui学习笔记--css(常用组件16)--文章页Article 一.总结 1.基本使用:文章内容页的排版样式,包括标题.文章元信息.分隔线等样式. .am-article 文章内容容器 .a ...

  8. amazeui学习笔记--css(常用组件15)--CSS动画Animation

    amazeui学习笔记--css(常用组件15)--CSS动画Animation 一.总结 1.css3动画封装:CSS3 动画封装,浏览器需支持 CSS3 动画. Class 描述 .am-anim ...

  9. amazeui学习笔记--css(常用组件14)--缩略图Thumbnail

    amazeui学习笔记--css(常用组件14)--缩略图Thumbnail 一.总结 1.基本样式:在 <img> 添加 .am-thumbnail 类:也可以在 <img> ...

随机推荐

  1. 代码片段快捷键 CodeSnippets

    CodeSnippets https://github.com/jaydee3/CodeSnippets These are my Xcode 4 CodeSnippets. To use them, ...

  2. 【JavaScript】DOM之事件

    DOM 事件 1.事件是什么 让JS知道程序用户行为,比如用户点击HTML页面中的某个按钮和用户输入用户名与密码等操作 <script> var button = document.get ...

  3. mui初级入门教程(一)— 小白入手mui的学习路线

    文章来源:小青年原创发布时间:2016-05-15关键词:mui,html5+转载需标注本文原始地址:http://zhaomenghuan.github.io/#!/blog/20160515 写在 ...

  4. rpm --qf 命令

    1. 环境准备: sudo apt-get install rpm (Ubuntu系统) wget ftp://rpmfind.net/linux/fedora-secondary/developme ...

  5. 不同vlan之间相互通信

    不同VLAN之间相互通信的两种方式 (单臂路由.三层交换) 试验目的: 1.通过单臂路由实现不同VLAN之间的通信 2.通过三层交换路由功能实现不同VLAN之间的通信   网络拓扑图: 1.单臂路由实 ...

  6. python匿名函数应用--动态计算器

    匿名函数: 一般用于函数体较为简单的运算,和一些不需要函数名的传递.  lambda 参数1:运算举例:  func = lambda x,y:x+y :可以给匿名函数添加变量名. 匿名函数的应用: ...

  7. cts-verifier测试流程

    测试目的: cts的补充测试,可以理解为没法自动化的cts测试,这个是人工测试. 测试前提: 1.发货user版本 2.selinux:Enable 5.外网环境 设备需求: 2个待测设备:1个手机或 ...

  8. 【ABAP系列】SAP webservice HTTP框架出错 404错误

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP webservice H ...

  9. 02 - Jmeter4.x正则表达式以及跨线程使用变量

    话不多说 直接开撸 上图可以看出,有两个请求,其中第二个请求返回了登录超时,结合第一个登录接口来看,这个是需要header请求内容的也就是 token:当然设置一个token又怎么可能难得倒我们,无非 ...

  10. [Linux] 017 网络命令与挂载命令

    1. 网络命令:write 命令名称:write 命令所在路径:/usr/bin/write 执行权限:所有用户 语法:write [用户名] 功能描述:给用户发信息,以 Ctrl-d 保存结束 范例 ...