MobX基础使用

245 阅读2分钟

MobX是什么

mobx通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。

核心原理

利用defineProperty(<=v5)或Proxy(v6)拦截对象属性的变化,实现数据的Observable,在 get 中依赖收集,set 中触发依赖绑定的监听函数。

原则

事件触发action更新 observable 状态

observable 状态的变更会被精确地传送到中所有依赖于它们的计算和副作用里。

image.png

安装

mobx包,提供了 MobX 所有的与具体框架平台无关的基础 Api

react-mobx包,针对react开发提供的包

$ npm i mobx react-mobx

react 开发中,如果只使用函数式组件,不使用类组件,那么可以将 mobx-react 替换为轻量的包 mobx-react-lite

$ npm i mobx mobx-react-lite

使用

store

官方推荐使用类的方式声明store

使用 类+makeObservable 需要手动声明注解

const {
  observable,
  action,
  computed,
  makeObservable,
  autorun,
  flow,
} = require("mobx");

class CountStore {
  count;
  total;
  constructor(count) {
    this.count = count;
    makeObservable(this, {
      count: observable,
      total: observable,
      doubleCount: computed,
      addCount: action,
      addTotal: action,
      fetchData: flow,
    });
  }

  get doubleCount() {
    console.count("执行次数是:");
    return this.count * 2;
  }

  addCount = () => {
    this.count++;
  };

  addTotal = () => {
    this.total++;
  };

  *fetchData() {
    const res = yield fetch("/v1/mock");
  }
}

const counter = new CountStore(0);

// 每当关联的值发生变化时,自动运行副作用。
autorun(() => {
  console.log("autorun", counter.doubleCount);
});

console.log("doubleCount ", counter.doubleCount); // 不会重新计算

counter.addCount();

counter.addTotal();

annotations

  • observable: 属性,完整的对象,数组,Maps 和 Sets 都可以被转化为可观察对象。

  • action:action 就是任意一段修改 state 的代码

  • flow:处理异步操作,makeAutoObservable会把 generators 自动推断成 flow

  • computed:计算值可以用来从其他可观察对象中派生信息。 计算值采用惰性求值,会缓存其输出,并且只有当其依赖的可观察对象被改变时才会重新计算。 它们在不被任何值观察时会被暂时停用。

使用 类+makeAutoObservable

makeAutoObservable就像是加强版的makeObservable,在默认情况下它将推断所有的属性。也可以重写注解的默认行为

  • 属性会成为observable
  • getters会成为computed
  • setters会成为action
  • function会成为autoAction
  • generator functions会成为flow
import { makeAutoObservable } from "mobx";

class CountStore {
  count;
  constructor(count) {
    this.count = count;
    makeAutoObservable(this);
  }

  get doubleCount() {
    return this.count * 2;
  }

  addCount = () => {
    this.count++;
  };

  *fetchData() {
    const res = yield fetch("/v1/mock");
  }
}

export default CountStore;

集成React

MobX 可以独立于 React 运行, 但是他们通常是结合在一起使用

Mobx使用单向数据流,利用 action 改变 state ,每当关联的值发生变化时,自动重新渲染组件

HOC方式,使用 observer 包裹React Component

import React from "react";
import { Button } from "antd";
import { makeAutoObservable } from "mobx";
import { observer } from "mobx-react";

class CountStore {
  count;
  constructor(count) {
    this.count = count;
    makeAutoObservable(this);
  }

  get doubleCount() {
    return this.count * 2;
  }

  addCount = () => {
    this.count++;
  };
}

export const store = new CountStore(0);

const Demo1 = () => {
  const { count, addCount } = store;
  return <Button onClick={() => addCount()}>{count}</Button>;
};

export default observer(Demo1);

使用hooks useObserver

import React from "react";
import { useObserver } from "mobx-react";
import { Button } from "antd";
import { store } from "./demo1";

const Demo2 = () => {
  return useObserver(() => {
    const { doubleCount, addCount } = store;

    return <Button onClick={addCount}>{doubleCount}</Button>;
  });
};

export default Demo2;

使用<Observer>组件(通常使用在回调组件上)

使用useLocalObservable定义组件内state

import React from "react";
import { Observer, useLocalObservable } from "mobx-react";
import { Button } from "antd";

const Row = ({ render }) => {
  return <div>{render()}</div>;
};

const Demo3 = () => {
  const localStore = useLocalObservable(() => ({
    localCount: 1,
    localAddCount() {
      this.localCount++;
    },
  }));

  return (
    <Row
      render={() => (
        <Observer>
          {() => {
            const { localAddCount, localCount } = localStore;
            return <Button onClick={localAddCount}>{localCount}</Button>;
          }}
        </Observer>
      )}
    />
  );
};
export default Demo3;

与Redux相比

数据是否可变

Redux 期望所有状态更新都是使用不可变的方式。reducer总是返回一个新的状态,而不是改变你的状态,reducer不执行状态突变或依赖对象引用。在原理上禁止使用 mutable方式修改状态。

Mobx使用可变数据结构,使用熟悉的 JavaScript 赋值就行,原则上只能使用action来修改状态,但是也可以直接修改去修改状态,让项目变得更加不可维护。

存储的数据结构

Redux默认是存储的一个原生的JavaScript对象,而MobX则是存储了一个可观察的对象。

哪个更好?

抛开实际项目使用不谈?我认为xxx更好
任何的对比都应在实际项目使用中