Mobx入门

166 阅读2分钟

解决什么问题

为前端应用程序提供整套的状态管理方案。

使用过Redux的小伙伴也许会有疑问,Redux不是已经实现了嘛,为什么还有Mobx

搞事情???

我也想知道...

带着这个疑问,来看下Mobx是如何为前端应用提供状态管理方案的,探寻我们想要的答案。

如何解决的

Mobx 区分了应用程序中的以下三个概念:State(状态)、Actions(动作)、Derivations(派生)

image.png

官网有一个比喻,Mobx 把整个应用程序比作 Excel 表格,State 是保存着数据的单元格,Actions 像是用户在单元格中输入了新的值,Derivations 类似于 Excel 中的公式。

State

State 是驱动应用程序的数据。State 可以存储任意类型的数据,例如:普通对象、数组、类等。

以一个经典的 Todo 作为例子,使用 Mobx 声明如下:

import { makeObservable, observable, action } from 'mobx'

class Todo {
  id = Math.random()
  title = ''
  finished = false

  constructor (title) {
    makeObservable(this, {
      title: observable,
      finished: observable,
      toggle: action
    })
    this.title = title
  }

  toggle () {
    this.finished = !this.finished
  }
}

Actions

Action 是任意可以改变 State 的代码,比如用户事件处理、后端返回数据处理等。

在上面的例子中,toggle改变了finished属性的值,所以它就是一个 action 。

Derivations

任何通过 State 能够生成的东西都是 Derivations。比如用户界面(依赖于State中的数据)、派生的数据等。

Mobx 区分两种 Derivations:

  • Computed Values: 可以通过 State 推导出来的数据;
  • Reactions: 当 State 改变时,需要自动运行的副作用;

Computed

在以上 Todo 例子的基础上,继续用 Mobx 声明 TodoList。

import { makeObservable, observable, computed } from 'mobx'

class TodoList {
  todos = []

  get unfinishedTodoCount () {
    return this.todos.filter(item => !item.finished).length
  }

  constructor (todos) {
    makeObservable(this, {
      todos: observable,
      unfinishedTodoCount: computed // <-
    })
    this.todos = todos
  }
}

Reactions

前面已经有 Todo, TodoList 的数据模型了,接下来可以写视图层的代码了。

const TodoListView = observer(({ todoList }) => { 
  // 注意 todoList 参数外层需要包裹一层 {},否则后面取数就会有问题
  console.log(todoList)
  return (
    <div>
      <ul>
        {todoList.todos.map(item => (<TodoView key={item.id} todo={item} />))}
      </ul>
    </div>
  )
})

const TodoView = observer(({ todo }) => {
  console.log(todo.title, todo.finished)
  return (
    <div>
      <input type='checkbox' checked={todo.finished} onChange={() => todo.toggle()} />
      <div>{todo.title}</div>
    </div>
  )
})

const store = new TodoList([new Todo('learn Mobx'), new Todo('learn TS')])

export default function Demo () {
  return <TodoListView todoList={store} />
}

在调试过程中,可能需要在每次 State 改变时,输出最新 State 的数据。除了像上面例子中在视图层打印之外(稍微有点Low),还可以在数据层的 constructor 中添加如下代码:

class Todo {
    constructor (title) {
        // other code...
        autorun(() => {
          console.log(this.title, this.finished)
        })
    }
}

小结

比起 Redux 需要编写 actionCreater,reducer,saga/thunk 等样板代码,Mobx 在使用上是否感觉方便了许多呢?这也许就是在 Redux 占领 React 项目大片江山的情况下,Mobx 依然能够成为一方诸侯的主要原因。