MobX 入门教程

发布于 2021-06-28 20:14:20 字数 5310 浏览 1376 评论 0

大家用 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, DerivationsReactions

可以拿 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

已经忘了多久

文章 0 评论 0

15867725375

文章 0 评论 0

LonelySnow

文章 0 评论 0

走过海棠暮

文章 0 评论 0

轻许诺言

文章 0 评论 0

信馬由缰

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文