一:Mobx介绍
mobx——简单、可扩展的状态管理库. 通过透明的
函数响应式编程使得状态管理变得简单和可扩展
使用原理:

名词概念:
State:状态,应用依赖的最小状态集,没有任何多余的状态,也不需要通过其他状态计算而来的中间状态;
Computed value:计算值,是根据state推导计算出来的值;
Reaction:响应,受state影响,会对state的变化做出一些更新ui、打印日志等反应;
Action:动作,建议是唯一可以修改状态的方式;
Mobx整体是一个观察者模式,存储state的store是被观察者,observable是观察者。当action改变中的state的store之后,computed value和reactin会自动根据state的改变做最小化更新,需要注意的是computed value采用延迟更新的方式,只有待更新的computed value被使用时才会被重新计算,否则computed value不会被重新计算,将被自动回收。
二:安装
第一步:创建一个react项目
npx create-react-app mobx-study
// 进入当前app
cd mobx-study
第二步:创建安装mobx的环境
方法一
1、配置package.json,需要先将隐藏的webpack配置暴露出来
npm run eject
// 需要注意的是 运行之前要将代码先提交一遍,也就是说git commit一次
git add.
git commit -m ""
因为使用creata-react-app脚手架构建react项目的时候package.json,只有三个依赖,分别是react,react-dom,react-scripts,像webpack,babel等等都是被creat react app封装到了react-scripts这个项目当中,包括基本启动命令 都是通过调用react-scripts这个依赖下面的命令进行启动的,creat react app搭建出来的项目默认支持以下命令:start以开发模式启动项目,build将整个项目进行构建,test进行测试,eject,会将原本creat react app对webpack,babel等相关配置的封装暴露出来,而至于说为什么要提交一下,是因为是脚手架添加了.gitignore这个文件,但是没有本地仓库
2、安装插件
npm install --save-dev babel-plugin-transform-decorators-legacy
// 修饰符的插件
npm install @babel/plugin-proposal-decorators
// 装饰器的一个插件
3、然后在package.json文件中配置babel
"babel": {
"plugins":[
[
"@babel/plugin-proposal-decorators",
{
"legacy":true
}
],
[
"@babel/plugin-proposal-class-properties",
{
"loose":true
}
]
],
"presets": [
"react-app"
]
},
方法二:
// 安装插件
npm install --save-dev babel-plugin-transform-decorators-legacy
// 修饰符的插件
npm install @babel/plugin-proposal-decorators
// 装饰器的一个插件
在根目录下面新建一个.babelrc文件,输入
"babel": {
"plugins":[
[
"@babel/plugin-proposal-decorators",
{
"legacy":true
}
],
[
"@babel/plugin-proposal-class-properties",
{
"loose":true
}
]
],
"presets": [
"react-app"
]
},
第三步:安装mobx
npm install mobx mobx-react --save
三:observable相关
@observable —— 将属性转化为可观察的 观察者
我们知道mobx中的state状态就是驱动应用时的数据,而这个数据是需要被观察的,在mobx中就使用了observable来对数据进行观测
使用方法:
1、
classProperty = observable(value);2、
@observable classProperty = value; // 装饰器写法@observable的value值可以是JS基本类型、引用类型、普通对象、类实例、数组、映射
注意:第二种装饰器的写法必须在有装饰器的环境下才能使用,否则的话可以使用decorate
Observable转换规则
| 类型 | 转化后类型 |
|---|---|
| ES6 Map实例 | Observable Map |
| 数组 | Observable Array |
| 没有原型的对象 | Observable Object |
| 有原型的对象,js原始类型,函数 | 转化后返回boxed Observable |
这里引入了一个boxed Observable
使用:observable.box(value) 接受任何值并把值存储到盒子里面,使用.get获取属性,使用.set(value)更新属性
可以转换的类型:
js基本数据类型—— 转换原理:将包含原始类型值得属性转换为可观察的,因为原始类型值是不可变的,所以值不能被观察
@observable count = 1;
数组类型——返回Observable Array,当数组元素的增加、减少或者元素对象的属性改变时,会触发更新
@observable list = [1, 2, 3, 4];
对象类型
如果value是没有原型的对象(例如:{key: 'key', value: 'value'}普通对象是指不是使用构造函数创建出来的对象,而是以 Object 作为其原型,或者根本没有原型。 ),则该对象会被克隆,并且其所有的属性都会被转换为可观察的;如果value是有原型的对象(例如:new MyClass()),MobX 不会将一个有原型的对象自动转换成可观察的,在类定义上使用 @observable / decorate
map
会返回一个新的 Observable Map。Map对象的每一个元素都是可观察的,并且向Map对象中添加和删除新的元素也是可观察的
四:对observable做出响应的方法
在使用方法之前,我们需要知道mobx一般都会对什么做出反应:
MobX 会对在追踪函数执行过程中读取存的可观察属性做出反应。
对属性进行观测,不是值“追踪函数” 是 computed 表达式、 when、reaction 和 autorun 的第一个入参函数
computed计算值
类似于Vue中的计算属性 经常用于一些表达式计算之类,如果引入的值发生变化的话,那么计算值就会根据状态自动进行重新计算,但是如果值没有变化,就不会触发,有一个缓存的概念存在。
需要注意的是:
1、计算值中如果观察的那个值没有发生变化,则计算属性不会触发更新
2、如果计算值不再被使用的时候,会默认回收,不再触发更新
写法:
// 引入装饰器写法
import {observable, computed} from "mobx";
class OrderLine {
@observable price = 0;
@observable amount = 1;
constructor(price) {
this.price = price;
}
@computed get total() {
return this.price * this.amount;
}
}
// 没有引入装饰器写法
import {decorate, observable, computed} from "mobx";
class OrderLine {
price = 0;
amount = 1;
constructor(price) {
this.price = price;
}
get total() {
return this.price * this.amount;
}
}
decorate(OrderLine, {
price: observable,
amount: observable,
total: computed
})
除此之外,还可以通过在observable.object 和 extendObservable 使用get函数,这两个都会自动的将getter属性推导成为计算属性
import {observable} from “mobx”;
const Money = observable.object({
price: 0,
amount: 1,
get total() {
return this.price * this.amount
}
})
console.log(Money.total) // 0
Money.price = 10;
console.log(Money.total) // 10
autorun
当数据改变的时候会自动执行,autorun方法中依赖的状态每变化一次,就会自执行一次
如果你有一个函数应该自动运行,但不会产生一个新的值,请使用autorun
var numbers = observable([1,2,3]);
var sum = computed(() => numbers.reduce((a, b) => a + b, 0));
var disposer = autorun(() => console.log(sum.get()));
// 输出 '6'
numbers.push(4);
// 输出 '10'
disposer(); // 清除autorun
numbers.push(5);
// 不会再输出任何值。`sum` 不会再重新计算。
还可以接收第二个参数,非必填:
delay: 可用于对效果函数进行去抖动的数字(以毫秒为单位)。如果是 0(默认值) 的话,那么不会进行去抖。name: 字符串,用于在例如像spy这样事件中用作此 reaction 的名称。onError: 用来处理 reaction 的错误,而不是传播它们。scheduler: 设置自定义调度器以决定如何调度 autorun 函数的重新运行
和computed的区别:
@computed 用于响应式的产生一个可以被其他 observer 使用的值;autorun 不产生新的值,而是达到一个效果(如:打印日志,发起网络请求等命令式的副作用);
@computed中,如果一个计算值不再被观察了,MobX 可以自动地将其垃圾回收,而 autorun 中的值必须要手动清理才行。
observer——类似于autorun
observer 函数/装饰器可以用来将 React 组件转变成响应式组件,由 mobx-react 包提供。
reaction
接收两个函数参数,第一个函数**引用可观察数据,并返回一个可观察数据**,作为第二个函数的参数。`reaction` **第一次渲染的时候,会先执行一次第一个函数**,这样 MobX 就会知道哪些可观察数据被引用了。随后在这些数据被修改的时候,执行第二个函数
import { observable, reaction } from 'mobx'
class Example {
@observable str = 'leo';
@observable num = 123;
@observable bool = false;
}
let example = new Example()
reaction(() => [example.str, example.num], arr => {
console.log(arr)
})
example.str = 'pingan'
example.num = 122
// ["pingan", 122]
// ["pingan", 122]
when
when会自动响应它使用state的变化,接收两个函数参数,第一个函数必须根据可观察数据来返回一个布尔值,当该布尔值为 true 时,才会去执行第二个函数,并且只会执行一次。,然后 autorunner(自动运行程序) 会被清理。 该函数返回一个清理器以提前取消自动运行程序。
constructor(){
when(() => this.hasNotFinished.length === 0, () => {
this.disposer();
this.reaction();
});
}
@computed get hasNotFinished(){
return this.todos.filter(item => item.finished === false);
}
when比较适合用在以响应式的方式执行取消或清除逻辑的场景;最多执行一次;when返回一个清理器,可以在需要时提前清除
五:改变observable
action——可以修改状态
可以在任意位置修改状态,但是推荐使严格模式,在严格模式下,只能在action中修改状态。
使用方法:
action(fn)action(name, fn)@action classMethod() {}@action(name) classMethod () {}@action boundClassMethod = (args) => { body }@action(name) boundClassMethod = (args) => { body }@action.bound classMethod() {}
解释:
action装饰器/函数遵循 javascript 中标准的绑定规则。 但是,action.bound可以用来自动地将动作绑定到目标对象。 注意,与action不同的是,(@)action.bound不需要一个name参数,名称将始终基于动作绑定的属性
注:函数内多个修改状态的操作会被合并,全部修改完后会通知computed和reaction
应该永远只对修改状态的函数使用动作。 只执行查找,过滤器等函数不应该被标记为动作
推荐使严格模式,在严格模式下,只能在action中修改状态。
注意action.bound不要和箭头函数一起使用;箭头函数已经是绑定过的并且不能重新绑定
不同版本开启严格模式的方法:
1、mobx@3.x:useStrict(boolean)
2、mobx@4.x:configure({ enforceActions: boolean })
3、mobx@5.x:configure({ enforceActions: value })
value可接收的值为:
"never" (默认): 可以在任意地方修改状态
"observed": 在某处观察到的所有状态都需要通过动作进行更改。在正式应用中推荐此严格模式。
"always": 状态始终需要通过动作来更新。
六:工具函数
https://cn.mobx.js.org/refguide/tojson.html
mobx6
makeObservable :用于捕获现有对象属性并使它们可观察
用法:
// target: 将目标对象中的属性和方法设置为 observable state 和 action
// overrides: 覆盖默认设置, 将 target 对象中的某些属性或者方法设置为普通属性
// options: 配置对象, autoBind, 使 action 方法始终拥有正确的 this 指向
makeAutoObservable(target, overrides?, options?)
makeAutoObservable(this, {reset: false}, {autoBind: true})