MobX 入门教程
大家用 redux 这么久,有没有被那么多概念和约定烦到?比如:
- 一个 click 的事件需要经过 action, dispatch, middleware, reducer 才能走完流程
- reducer 里不能直接修改 state,而是每次返回一个新的
- 要区分 container 和 component
- container 里要在 connect 里 select 数据,一不小心就选多了或选少了,出于性能考虑还要借助 reselect 这个库
- 发异步请求需要借助 redux-thunk 或 redux-saga
如果有,那么可以尝试下 mobx 。
什么是 mobx
mobx 只做一件事,解决 state 到 view 的数据更新问题。
mobx 是一个库 (library),不是一个框架 (framework)。他不限制如何组织代码,在哪里保存 state 、如何处理事件,怎么发异步请求等等。我们可以回归到 Vanilla JavaScript,可以和任意类库组合使用。
核心理念
mobx 引入了几个概念,Observable state
, Derivations
和 Reactions
。
可以拿 Excel 表格做个比喻,Observable state
是单元格,Derivations
是计算公式,单元格的修改会触发公司的重新计算,并返回值,而最终公式的计算结果需要显示在屏幕上(比如通过图表的方式),这是 Reactions
。
下面通过代码理解下这些概念,以 mobx 和 react 的组合使用为例:(Open Demo on jsfiddle)
import { observable, computed } from 'mobx';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
////////////////////
// Store
class TodoStore {
@observable todos = [];
@computed get completedTodosCount() {
return this.todos.filter(todo => todo.completed === true).length;
}
addTodo(task) {
this.todos.push({ task, completed: false });
}
}
////////////////////
// Components
@observer
class TodoList extends Component {
render() {
const { todoStore } = this.props;
return (
<div>
{ todoStore.todos.map((todo, index) => <Todo todo={todo} key={index} />) }
Progress: { todoStore.completedTodosCount }
</div>
);
}
}
@observer
class Todo extends Component {
render() {
const { todo } = this.props;
return (
<li onDoubleClick={this.onRename}>
<input
type="checkbox"
checked={ todo.completed }
onChange={ this.onToggleCompleted }
/>
{ todo.task }
</li>
);
}
onToggleCompleted = () => {
const todo = this.props.todo;
todo.completed = !todo.completed;
}
onRename = () => {
const todo = this.props.todo;
todo.task = prompt('Task name', todo.task) || "";
}
}
////////////////////
// Init
const todoStore = new TodoStore();
todoStore.addTodo('foo');
todoStore.addTodo('bar');
ReactDOM.render(
<TodoList todoStore={todoStore} />,
document.getElementById('mount')
);
这里通过 @observable
定义 Observable state
,通过 @computed
定义 Derivations
,通过 @observer
封装了 React Component 的 render 方法,这是 Reactions
。
为什么用 mobx
mobx 官网 罗列了不少区分与 flux 框架的优点,这里摘录一些比较打动我的。
简单
没有 connect,没有 cursor,没有 Immutable Data ... 总之感觉会少很多代码。同时概念也更少。
可以用 class 来组织和修改数据
对于组织复杂的领域模型比较适用。
可以用 JavaScript 引用来组织和修改数据
比如,可以直接
todo.completed = true;
而不需要
return todos.map((todo) => { if (todo.id === action.payload.id) { return {...todo, {completed: true}} else { return todo; } });
同时也不需要引入额外的 immutable.js。
性能相比 redux 有优势
mobx 会建立虚拟推导图 (virtual derivation graph),保证最少的推导依赖。dan_abramov 亲自操刀为 todoMVC 做了极致的优化才和 mobx 打成平手。链接
不足
参考之前 redux + redux-saga 的方案,这里的一些点可能会成为你我不用他的原因。
浏览器兼容性,不支持 IE8
由于用了 reactive arrays, objects with reactive properties (getters) 这些 ES5 特性,而且这些特性不能通过 es5-shim 解决。兼容列表可参考:http://kangax.github.io/compat-table/es5/
缺少最佳实践
这部分不在 mobx 的范围之内,需要自己探索一套最佳实践。比如如何触发 action,如何组织 store,如何组织业务逻辑,如何发异步请求,如何在 React Component 之间传递数据等等。
热替换 (Hot Module Replacement)
用过 HMR,就不愿再回到手动刷页面的时代。mobx 支持 [react-transform] 的热替换方式,但是否支持 webpack 原生热替换情况下对 store 进行替换,还有待探索。
总结
mobx 简单高效,在用吐了 redux 之后,对 mobx 简直爱不释手。除了不支持 IE8 这个硬伤,其他缺点都还是可以接受的。我会在后面的小项目中应用它,并尝试探索一套最佳实践。
扩展阅读
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论