Mobx 6

2,768 阅读4分钟

概念

mobx最新版本装饰器声明已经无效(只做标注),要实现Observable,Action等声明。必须makeObservable或者makeAutoObservable显性声明。

后来查了一下官方的提案,主要的原因是跟js的class语言标准不兼容才迫不得已修改的。 为什么和语言标准不兼容,最新的标准规定了class的属性应该是[[define]] 上去的而不是 [[set]]上去的: www.yuque.com/mosinng/blo…

Mobx5代码

import {observable, computed, action, makeObservable} from "mobx"

class TodoStore {
    @observable todos: Todo[] = []

    @computed
    get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.done).length
    }

    @action
    addTodo(todo: Todo) {
        this.todos.push(todo)
    }
}

Mobx6代码

class TodoStore {
    todos: Todo[] = []

    constructor() {
        makeObservable(this, {
            todos: observable,
            unfinishedTodoCount: computed,
            addTodo: action
        })
    }

    get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.done).length
    }

    addTodo(todo: Todo) {
        this.todos.push(todo)
    }
}

或者:

class TodoStore {
   todos: Todo[] = [];

    constructor() {
        makeAutoObservable(this);
    }

    get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.done).length
    }

    addTodo(todo: Todo) {
        this.todos.push(todo)
    }
}

mobx:MobX 核心库

mobx-react-lite:仅支持函数组件

mobx-react:既支持函数组件也支持类组件

 "dependencies": {
    "mobx": "^6.1.4",
    "mobx-react": "^7.1.0",
    "mobx-react-lite": "^3.2.0",
  },

Mobx6变化

  • 在 Mobx 6 以前,一直提倡的是装饰器语法,但是自从 Mobx 6 开始不再建议使用装饰器,以便最大程度的贴近 JS 标准

  • 将数据变成可观察的有 makeObservable, makeAutoObservable, observable 三个 Api

  • 三个Api 比较起来 makeAutoObservable 是最方便的,但是,makeAutoObservable 处理的”类“是不可以具有 super subClass 等继承关系的,这对封装 store 会造成一些麻烦

  • makeObservable, makeAutoObservable 都可以用来将对象转化为 "可观察对象"。他们的 api 大同小异,其中 makeObservalble 需要通过第二个参数,来确定对象的属性怎么转化成 Observerable。makeAutoObservable 也有第二个参数,是选填的,与 makeObservalble 的写法一样,不过 makeAutoObservable 会自动判断,第二个参数只是用作覆盖自动判断的结果。

  • observable 具有与 makeAutoObservable 相同的 参数配置,但是它不会将源对象转变为 Observable, 而是创建一个新的 Observable 对象, 同时创建的对象是通过 proxy 包裹的,可以追加新的属性, make(Auto)Observable 不能直接追加新的属性,追加后,新的属性不具有响应能力 理论上 make(Auto)Observable 修改后的对象是非 Proxy 对象,处理速度上会更快, 因此 建议使用 make(Auto)Observable 并提前确定好属性

  • extendObservable 用来给已有对象,追加其他 Obser vable 属性

  • observable.box 用来将简单类型变成 Observable, 对其他 Api 来讲,只有引用类型可以转换为 Observable, 这个 Api 专门用来处理简单类型数据 例如 string | number 。

  • mobx-react 提供 useLocalObservable 可以代替 useState 来给 函数式组件提供 ”可观察的“ state

206988 113251 180396 86659 应补868.8

将 React 组件变成“观察者”

  • “mobx-react” 会提供一个名为 observer 的 HOC 帮助我们将组件变成观察者
  • 成为观察者的组件,只有在当前组件内使用的 “可观察数据” 发生改变时才会重新 render 组件,否则组件不做更新,从而提高性能
  • 可观察数据一般是一个对象,而且这个对象的值可能变化,但是引用地址不会改变
  • observer 相当于帮我们做了 pureComponent\memo,而且控制 render 的更加精细
  • 没有使用 “可观察数据” 的组件,应改为使用 React.memo | React.PureComponent 来增强性能

MobX 概念及结合 React 的简单使用

  • State:数据
  • Derivations: 派生,是一些由 state 计算而来的数据
  • Reactions: 反应,与派生类似,但是不会生成数据,而是会执行某些任务,一般用来DOM更新或者网络请求
  • Actions:行动,所有对 state 的改动都应在这里进行,Action 中触发的 state 改动又会自动的触发 Derivations 及 Reactions
  • 没有了类似 Redux 容器组件、UI 组件的区分,所有组件都是可以是 observer

MobX 结合 React 使用

  • 通过 mobx 创建 “可观察”的数据(Observable)
  • 借助 “mobx-react” 将 react 组件变成 观察者,观察者也就是 mobx 概念中 Reactions 反应与组件的结合产物
  • React 组件中某些操作触发 action 执行,由此就完成了一个闭环

Mobx Api

  • toJS() 用于将 ”可观察数据“ 转化为普通 JS 数据类型
  • isObservable:数据类型判断
  • comparer.structural: 深层比较两个 observable 数据的值是否相等
  • 其他。。。。。

Using flow instead of async / await {🚀}

然而,更好的方式是使用 flow 的内置概念。它们使用生成器。一开始可能看起来很不适应,但它的工作原理与 async / await 是一样的。只是使用 function * 来代替 async,使用 yield 代替 await 。 使用 flow 的优点是它在语法上基本与 async / await 是相同的 (只是关键字不同),并且不需要手动用 @action 来包装异步代码,这样代码更简洁。

import { makeObservable, observable, computed, action, flow } from "mobx"

export default class CounterStore {
  count = 3;
  state = "pending";
  
  constructor() {
    makeObservable(this, {
      count: observable,
      state: observable,
      doubleCount: computed,
      increment: action, // Mark a method as an action that will modify the state
      decrement: action,
      fetchProjects: flow // Creates a flow to manage asynchronous processes.
    });
  }
  
  increment() {
    console.log('increment');
    this.count++;
  }
  
  decrement() {
    this.count--;
  }
  
  get doubleCount() {
    return this.count * 2;
  }
  
  // Note the star, this a generator function!
  *fetchProjects() {
    this.state = "pending";
    try {
      // Yield instead of await.
      const response = yield fetch("/api/value");
      this.value = response.json();
      this.state = "done";
    } catch (error) {
      this.state = "error"
    }
  }
}

参考:

blog.csdn.net/mjzhang1993… mobx.js.org/actions.htm… www.ithere.net/article/409

segmentfault.com/a/119000003…