Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mobx #104

Open
Twlig opened this issue Jul 14, 2022 · 0 comments
Open

mobx #104

Twlig opened this issue Jul 14, 2022 · 0 comments
Labels

Comments

@Twlig
Copy link
Owner

Twlig commented Jul 14, 2022

mobx

mobx是一个集中式状态管理库,用于解决组件间状态(State)共享问题。

mobx中有三个重要的概念:State,Actions,Derivations。

  1. State是状态信息。使用 Proxy 包装。

  2. Actions是动作,其实就是一个函数,调用Action更新State

  3. Derivations是派生信息,是由State状态衍生出来的,比如在State中有用户的fristName和lastName,fullName属性应该是通过state中的fristName和lastName派生出来。

    Derivations有两种:

    • Computed values,总是可以通过纯函数从当前的可观测 State 中派生。
    • Reactions, 当 State 改变时需要自动运行的副作用 (命令式编程和响应式编程之间的桥梁)

注意:如果在state中直接存储fullName,会导致变更firstName的同时,去触发fullName的变更,才能保证数据的统一性。因此,直接派生fullName是更合理的做法。

基础用法

  1. makeObservable

  • makeObservable(target, annotations?, options?)

    一般在类的构造函数中调用。

import { makeObservable, observable, computed, action, flow } from "mobx"

class Doubler {
    value
    constructor(value) {
        //参数1: target 把谁变成响应式(可观察)
        //参数2: 指定哪些属性或者方法变成可观察
        makeObservable(this, {
            value: observable,
            double: computed,
            increment: action.bound,//绑定this,使用的时候可以不用处理this指向问题
            fetch: flow  //创建一个 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?)

    在默认情况下它将推断所有的属性。

    推断规则:

    • 所有 自有 属性都成为 observable
    • 所有 getters 都成为 computed
    • 所有 setters 都成为 action
    • 所有 prototype 中的 functions 都成为 autoAction
    • 所有 prototype 中的 generator functions 都成为 flow。(需要注意,generators 函数在某些编译器配置中无法被检测到,如果 flow 没有正常运行,请务必明确地指定 flow 注解。)
    • overrides 参数中标记为 false 的成员将不会被添加注解。例如,将其用于像标识符这样的只读字段。
import { makeAutoObservable } from "mobx"

class Doubler {
    value
    constructor(value) {
        //参数1: target 把谁变成响应式(可观察)
        //参数2: 排除不需要被观察的属性或者方法
        //参数3: 选项,如是否自动绑定this
        makeAutoObservable(
            this, 
            {double: false,}, //double排除,不观察
            {autoBind: true}
        )
        this.value = value
    }
    get double() {
        return this.value * 2
    }
    increment() {
        this.value++
    }
    *fetch() {
        const response = yield fetch("/api/value")
        this.value = response.json()
    }
}

function createDoubler(value) {
    return makeAutoObservable({
        value,
        get double() {
            return this.value * 2
        },
        increment() {
            this.value++
        }
    })
}
  1. observable

  • observable(source, overrides?, options?)

与第一个例子中的 makeObservable 不同,observable 支持为对象添加(和删除)字段。 这使得 observable 非常适合用于像动态键控的对象、数组、Maps 和 Sets 之类的集合。

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")
  1. action

  • runInAction(fn)

使用这个工具函数来创建一个会被立即调用的临时 action。一次

import { observable, runInAction } from "mobx"

const state = observable({ value: 0 })

runInAction(() => {
    state.value++
    state.value++
})
  • 异步action

在处理 Promise 时,更新 state 的处理程序应该被 action 包装起来,或者被标记为 actions。

import { action, makeAutoObservable } from "mobx"

class Store {
    githubProjects = []
    state = "pending" // "pending", "done" or "error"

    constructor() {
        makeAutoObservable(this)
    }

    fetchProjects() {
        this.githubProjects = []
        this.state = "pending"
        fetchGithubProjectsSomehow().then(
            action("fetchSuccess", projects => {
                const filteredProjects = somePreprocessing(projects)
                this.githubProjects = filteredProjects
                this.state = "done"
            }),
            action("fetchError", error => {
                this.state = "error"
            })
        )
    }
}
  1. reactions

reactions 是需要理解的重要概念,因为他可以将 MobX 中所有的特性有机地融合在一起。 reactions 的目的是对自动发生的副作用进行建模。 它们的意义在于为你的可观察状态创建消费者,以及每当关联的值发生变化时,自动运行副作用。

  • autorun(effect: (reaction) => void)

    Autorun 通过在响应式上下文运行 effect 来工作。在给定的函数执行期间,MobX 会持续跟踪被 effect 直接或间接读取过的所有可观察对象和计算值。 一旦函数执行完毕,MobX 将收集并订阅所有被读取过的可观察对象,并等待其中任意一个再次发生改变。 一旦有改变发生,autorun 将会再次触发,重复整个过程。

    注意:autorun和runInAction的区别,autorun是自动触发会多次执行,runInAction是立即执行一次。

reactions使用原则:

  • 只有在引起副作用的一方与副作用之间没有直接关系的情况下才使用 reaction
  • reactions 不应该更新其他可观察对象
  • reactions 应该是独立的

observer

mobx负责做状态管理,那么状态变更如何触发视图的更新呢? mobx-react或者mobx-react-lite库的observer HOC 提供了状态更新触发视图更新的功能。

observer 将自动订阅 React components 中任何 在渲染期间 被使用的 可被观察的对象 。 因此, 当任何可被观察的对象 变化 发生时候 组件会自动进行重新渲染(re-render)。 它还会确保组件在 没有变化 发生的时候不会进行重新渲染(re-render)。 但是, 更改组件的可观察对象的不可读属性, 也不会触发重新渲染(re-render)。

import {observer} from 'mobx-react-lite'
import {createContext, useContext} from "react"

const TimerContext = createContext<Timer>()

const TimerView = observer(() => {
    // 从context中获取timer.
    const timer = useContext(TimerContext) // 可以在上面查看 Timer的定义。
    return (
        <span>Seconds passed: {timer.secondsPassed}</span>
    )
})

ReactDOM.render(
    <TimerContext.Provider value={new Timer()}>
        <TimerView />
    </TimerContext.Provider>,
    document.body
)
@Twlig Twlig added the react label Jul 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant