-
最近换到的新项目用到mobx,所以抽时间读了一下mobx文档,并总结了一下
关于MobX
-
Mobx是一个状态管理库,类似于Redux或者Vuex.
-
当我们开发vue或者react的SPA应用时,通常会使用prop等方式进行组件,当业务变得复杂,深层级的组件树中,不相关联的组件的通信变得异常困难。这时我们就需要引入集中式的状态管理库,Rudex/Vuex/Mobx都是这样的工具
Mobx核心
Observable state
- mobx的数据中心,会把普通对象变成一个ObservableObject
action
- 用来描述一个函数,通常用来给数据set值
Computed
- 描述对象中值的计算属性,类似于vue Computed
Reactions
- 数据改变造成的副作用,通常会有一个回调函数,用于数据或视图更新后的后续操作。类似于vue中watch
核心API
后面代码会写出Mobx的5种写法
- 可以根据个人习惯和项目类型更改不同写法。顺便解释一些核心api
写法1:makeObservable
import { makeObservable, observable, computed, action, flow } from "mobx"
class Doubler {
value
constructor(value) {
makeObservable(this, {
value: observable,
double: computed,
increment: action,
fetch: flow
})
this.value = value
}
get double() {
return this.value * 2
}
increment() {
this.value++
}
*fetch() {
const response = yield fetch("/api/value")
this.value = response.json()
}
}
解释下这段代码
-
makeAutoObservable
makeAutoObservable(target, overrides?, options?)
- makeAutoObservable参数,第一个是加入Observable的对象,第二个是重写实例的属性所对应的类型
- computed的函数带get; set函数叫做action; flow类型对应的用* yield语法处理promise函数,这里就是处理异步的事件
写法2:装饰器语法
import { observable, computed, action, flow } from "mobx"
class Doubler {
@observable accessor value
constructor(value) {
this.value = value
}
@computed
get double() {
return this.value * 2
}
@action
increment() {
this.value++
}
@flow
*fetch() {
const response = yield fetch("/api/value")
this.value = response.json()
}
}
写法3:函数返回值 + makeAutoObservable
import { makeAutoObservable } from "mobx"
function createDoubler(value) {
return makeAutoObservable({
value,
get double() {
return this.value * 2
},
increment() {
this.value++
}
})
}
makeAutoObservable
makeAutoObservable(target, overrides?, options?)
- All own properties become observable.
- All getters become computed.
- All setters become action.
- All functions become autoAction.
- All generator functions become flow. (Note that generator functions are not detectable in some transpiler configurations, if flow doesn't work as expected, make sure to specify flow explicitly.)
- Members marked with false in the overrides argument will not be annotated. For example, using it for read only fields such as identifiers.
- 成员重写属性设置为false是会跳出加入observable属性规则
makeAutoObservable({
test() {
// something
}
}, {
test: false
})
// 这里test函数不会被看作一个action函数
写法4:observable + 原生对象
import { observable } from "mobx"
const todosById = observable({
"TODO-123": {
title: "find a decent task management system",
done: false
}
})
todosById["TODO-456"] = {
title: "close all tickets older than two weeks",
done: true
}
const tags = observable(["high prio", "medium prio", "low prio"])
tags.push("prio: for fun")
- 这里用observable函数对原生对象的操作,使之成为ObservaleObject.更改ObservaleObject属性值都可以触发Reactions副作用
写法5:observable + 属性装饰器
import { observable, computed, action, flow } from "mobx"
class Doubler {
@observable value
constructor(value) {
makeObservable(this)
this.value = value
}
@computed
get double() {
return this.value * 2
}
@action
increment() {
this.value++
}
@flow
*fetch() {
const response = yield fetch("/api/value")
this.value = response.json()
}
}
- 总结:
- makeObservable,makeAutoObservable,@observable都是把数据变成 ObservableObject
- 值描述类型: observable, computed. 函数描述类型:action/ flow
Autorun和Reaction
Autorun
autorun(effect: (reaction) => void, options?)
- demo1
import { makeAutoObservable, autorun } from "mobx"
class Animal {
name
energyLevel
constructor(name) {
this.name = name
this.energyLevel = 100
makeAutoObservable(this)
}
reduceEnergy() {
this.energyLevel -= 10
}
get isHungry() {
return this.energyLevel < 50
}
}
const giraffe = new Animal("Gary")
autorun(() => {
console.log("Energy level:", giraffe.energyLevel)
})
autorun(() => {
if (giraffe.isHungry) {
console.log("Now I'm hungry!")
} else {
console.log("I'm not hungry!")
}
})
console.log("Now let's change state!")
for (let i = 0; i < 10; i++) {
giraffe.reduceEnergy()
}
- result:
Energy level: 100
I'm not hungry!
Now let's change state!
Energy level: 90
Energy level: 80
Energy level: 70
Energy level: 60
Energy level: 50
Energy level: 40
Now I'm hungry!
Energy level: 30
Energy level: 20
Energy level: 10
Energy level: 0
Reaction
autorun(effect: (reaction) => void, options?)
- demo2
import { makeAutoObservable, reaction } from "mobx"
class Animal {
name
energyLevel
constructor(name) {
this.name = name
this.energyLevel = 100
makeAutoObservable(this)
}
reduceEnergy() {
this.energyLevel -= 10
}
get isHungry() {
return this.energyLevel < 50
}
}
const giraffe = new Animal("Gary")
reaction(
() => giraffe.isHungry,
isHungry => {
if (isHungry) {
console.log("Now I'm hungry!")
} else {
console.log("I'm not hungry!")
}
console.log("Energy level:", giraffe.energyLevel)
}
)
console.log("Now let's change state!")
for (let i = 0; i < 10; i++) {
giraffe.reduceEnergy()
}
- result
Now let's change state!
Now I'm hungry!
Energy level: 40
- 这里都是副作用监听的回调函数
- 区别:autorun全部属性更改都会触发;reaction第一个参数的函数返回是对象中某个属性,指明是针对对应的某个属性监听后的effect副作用函数