解决什么问题
为前端应用程序提供整套的状态管理方案。
使用过Redux的小伙伴也许会有疑问,Redux不是已经实现了嘛,为什么还有Mobx?
搞事情???
我也想知道...
带着这个疑问,来看下Mobx是如何为前端应用提供状态管理方案的,探寻我们想要的答案。
如何解决的
Mobx 区分了应用程序中的以下三个概念:State(状态)、Actions(动作)、Derivations(派生)
官网有一个比喻,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 依然能够成为一方诸侯的主要原因。