mobx 简介

简单、可扩展的状态管理,相比于 redux,更轻巧,更简单,更灵活,在某些时候性能甚至更优越。

在这里简单的记录和介绍一下 mobx 的使用。

简单例子

import { observable } from "mobx";
import { observer } from "mobx-react";

var numStore = observable({
  num: 1,
  addNum: function () {
    this.num++;
  },
});

@observer
class TimerView extends React.Component {
  handleAdd = () => {
    this.props.numStore.addNum();
  };

  render() {
    return (
      <div>
        <span> num: {this.props.numStore.num} </span>
        <button onClick={this.handleAdd}></button>
      </div>
    );
  }
}

ReactDOM.render(<TimerView numStore={numStore} />, document.body);

主要的 api

observable

使用:

  • observable(value)
  • @observable classProperty = value

Observable 值可以是 JS 基本数据类型、引用类型、普通对象、类实例、数组和映射。 主要作用是指定该值的是被观察的、可修改的。其装饰器写法为 @observable。例如

import { observable, computed } from "mobx";

// 方法1,直接使用
var NumStore = observable({
  num: 1,
  addNum: function () {
    this.num++;
  },
});

// 方法二,装饰器写法
class NumStore {
  @observable price = 0;
  @observable num = 1;

  @computed get total() {
    return this.price * this.num;
  }
}

computed

如果任何影响计算值的值发生变化了,计算值将根据状态自动进行衍生。 计算值在大多数情况下可以被 MobX 优化的,因为它们被认为是纯函数。 例如,如果前一个计算中使用的数据没有更改,计算属性将不会重新运行。 如果某个其它计算属性或 reaction 未使用该计算属性,也不会重新运行。 在这种情况下,它将被暂停。

import { observable, computed } from "mobx";

class NumStore {
  @observable price = 0;
  @observable num = 1;

  @computed get total() {
    return this.price * this.num;
  }
}

autorun

autorun 可以用来监听值的变化,不要把 computedautorun 搞混。它们都是响应式调用的表达式,但是,如果你想响应式的产生一个可以被其它 observer 使用的值,请使用 @computed,如果你不想产生一个新值,而想要达到一个效果,请使用 autorun。 举例来说,效果是像打印日志、发起网络请求等这样命令式的副作用。

import axios from "axios";
import { observable, configure, action, runInAction, autorun } from "mobx";

configure({ enforceActions: "observed" });

export class Session {
  @observable num = 1;

  constructor() {
    autorun(() => {
      // 每次调用 addNum / subNum都会执行此函数
      console.log("auto log num:" + this.num);
    });
  }

  @action addNum = function () {
    console.log(this.num);
    this.num++;
  };

  @action subNum = () => {
    this.num--;
  };
}

export default new Session();

action

用法:

  • action(fn)
  • action(name, fn)
  • @action classMethod() {}
  • @action(name) classMethod () {}
  • @action boundClassMethod = (args) => { body }
  • @action(name) boundClassMethod = (args) => { body }
  • @action.bound classMethod() {}

action 主要是用来修改状态,也可以使用异步的方法

import axios from "axios";
import { observable, configure, action, runInAction } from "mobx";

// 强制使用 action 来修改状态,否则会打印 waring
configure({ enforceActions: "observed" });

export class Session {
  @observable num = 1;
  @observable loading = false;

  @action addNum = function () {
    console.log(this.num);
    this.num++;
  };

  @action subNum = () => {
    this.num--;
  };

  @action directGetHundred = () => {
    this.loading = true;
    setTimeout(
      // 所有的修改状态都需要放在 action 中
      action("directAddHundred", () => {
        this.num += 100;
        this.loading = false;
      }),
      1000
    );
  };

  @action directGetTwoHundred = async () => {
    this.loading = true;
    await axios("/");
    // 调用其他异步操作
    // await axios("/");
    // runInAction 是 action 的语法糖,鼓励你不要到处写 action,而是在整个过程结束时尽可能多地对所有状态进行修改
    runInAction(() => {
      this.loading = false;
      this.num += 200;
    });
  };
}

export default new Session();

flows

flows 的工作原理与 async / await 是一样的。只是使用 function * 来代替 async,使用 yield 代替 await 。 使用 flow 的优点是它在语法上基本与 async / await 是相同的 (只是关键字不同),并且不需要手动用 @action 来包装异步代码,这样代码更简洁。

flow 只能作为函数使用,不能作为装饰器使用。 flow 可以很好的与 MobX 开发者工具集成,所以很容易追踪 async 函数的过程。

mobx.configure({ enforceActions: true });

class Store {
  @observable githubProjects = [];
  @observable state = "pending";

  fetchProjects = flow(function* () {
    // <- 注意*号,这是生成器函数!
    this.githubProjects = [];
    this.state = "pending";
    try {
      const projects = yield fetchGithubProjectsSomehow(); // 用 yield 代替 await
      const filteredProjects = somePreprocessing(projects);
      // 异步代码块会被自动包装成动作并修改状态
      this.state = "done";
      this.githubProjects = filteredProjects;
    } catch (error) {
      this.state = "error";
    }
  });
}

总结

之前一直使用 redux,看到了有赞前端技术团队的 我为什么从 Redux 迁移到了 Mobx
文章,决定了解一下 mobx ,现在这里只记录 mobx 的简单使用,详细的还是需要查看官方文档


作者: Kavience 本文链接: http://www.kavience.com/frontend/study-and-use-of-mobx.html 转载请注明:《Mobx的学习与使用》转自 http://www.kavience.com/frontend/study-and-use-of-mobx.html,原作者:Kavience 版权声明: 自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)