读了一读Mobx官方文档

176 阅读3分钟
  • 最近换到的新项目用到mobx,所以抽时间读了一下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()
    }
}

解释下这段代码

  1. makeAutoObservable

makeAutoObservable(target, overrides?, options?)
  • makeAutoObservable参数,第一个是加入Observable的对象,第二个是重写实例的属性所对应的类型
  1. 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?)
  1. All own properties become observable.
  2. All getters become computed.
  3. All setters become action.
  4. All functions become autoAction.
  5. 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.)
  6. 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()
    }
}
  • 总结:
  1. makeObservable,makeAutoObservable,@observable都是把数据变成 ObservableObject
  2. 值描述类型: observable, computed. 函数描述类型:action/ flow

Autorun和Reaction

Autorun

autorun(effect: (reaction) => void, options?)
  1. 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?)
  1. 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副作用函数