mobx入门教程

背景

React的自身的状态本身由statesetState维护;但是随着应用复杂度的提升(组件间状态共享及状态变更),单纯通过setState进行状态管理的方案不仅变得代码复杂、难以维护,而且影响可扩展性;

针对这种状况,React目前主要有Reduxmobx两种解决方案(均可以让状态逻逻辑从展示组件等解耦出来,提高扩展性与复用性);


mobx与Redux有什么不同?

  1. Redux采用FP原则,核心为actionstorereducer,采用单一数据源,状态不可变更(总是返回一个新状态),使用纯函数进行状态变更;

    Redux更新时总是会返回一个新的state(redux底层的combineReducers会通过比较对象的引用来判断是否同一个对象,如果是的话则继续使用旧的state,即不会有任何UI更新,否则执行更新操作)

    为什么redux要求不可变性 ?

    1. 浅比较:redux的combineReducers及react-redux的connect方法
      生成的组件在比较根组件state与mapStateToProps函数返回值以确定是否更新时,都用到了浅比较;浅比较的前提是数据不可变;
    2. 不可变数据的管理极大地提升了数据处理的安全性。

    3. 进行时间旅行调试要求 reducer 是一个没有副作用的纯函数,以此在不同 state 之间正确的移动。

    什么是时间旅行?

    在 2015 年的 React Europe 会议上,Dan Abramov 展示了通过 Redux DevTools 让开发者在历史状态中自由穿梭, 提升调试体验

    时间旅行主要用于事件驱动的应用,比如富文本编辑器的状态回撤、游戏进度的读取和保存等等;具体参考从时间旅行的乌托邦,看状态管理的设计误区

    (state, action) => newState
    
  2. mobx采用OOP原则,也是响应式编程;采用observableobserver的概念,observable中将对象变为被观察对象,可以通过action等变更状态;observer定义观察对象,可以观察被观察对象的变更并应用;mobx状态是可变的,更加轻量级,入门比Redux简单;

    需要注意的是,MobX 在重绘时的性能优势是以访问劫持后更大的内存占用为代价的;(开箱即用的mobx与优化后的redux性能相当)

  3. 要点比较
    在这里插入图片描述
    在这里插入图片描述

Mobx概述

mobx支持单向数据流,由原始状态衍生的值都会自动变更,无法观察到中间值;

  1. 创建应用模型,定义状态使其可观察(建立store,即被观察对象)
  2. 创建视图以响应状态的变化(创建观察者,检测并响应状态变化)
  3. 更改状态

环境配置

mobx使用装饰器特性的话需要开启ES7的decorator属性;可以安装插件@babel/plugin-proposal-decorators"package.json中添加以下配置:

  "babel": {"plugins": [["@babel/plugin-proposal-decorators",{"legacy": true}]],"presets": ["react-app"]}

否则,可以借助mobx API —— decorate(object, decorators)实现部分功能


Mobx API —— observable相关

  1. 描述:observable用于创建被观察对象(定义可观察状态),需要注意的是被观察对象总是类的属性而不是值

  2. 用法:

    // 用法一, 会自动递归到整个对象
    observable(value)// 用法二 是extendObservable(this, { property: value})的语法糖
    @observable classProperty = value// demo
    import { observable, computed } from "mobx";class Order {@observable price = 0;@observable count = 1;@computed get total() {return this.price * this.count;}@action.boundincreasePriice() {this.price++;}
    }// demo2 —— 使用decorate重写demo
    import { observable, computed, decorate } from 'mobx';class Order {price = 0;count = 1;get total() {return this.price * this.count;}increasePriice() {this.price++;}
    }decorate(Order, {price: observable,count: observable,total: computed,increasePrice: action.bound
    })
    

Mobx API —— 对observable做出响应

1. computed——计算值

  • 含义:computed可以根据现有的状态或其他计算值衍生出新的值,并且这些值可以被observer使用;autorun主要适用于产生一个副作用而不是一个新值,如日志打印和网络请求等;

  • 要点:
    computed是响应式的,如果前一个依赖计算的值未发生变化,计算属性不会重新运行,这种情况下它会被暂停(自动暂停特性)。同时,如果一个计算属性不再被观察,其将会自动进行垃圾回收。

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

  • 用法:

    // 用法一:函数形式
    computed(expression)
    // demo
    import {observable, computed} from "mobx";
    var name = observable.box("John");var upperCaseName = computed(() =>name.get().toUpperCase()
    );var disposer = upperCaseName.observe(change => console.log(change.newValue));name.set("Dave"); // 输出: 'DAVE'// 用法二:装饰器。在任意属性的getter上使用
    @computed get propertyName() {return
    }

2. autorun——自定义反应

  • 含义:如果创建一个函数,本身不会有观察者,并且其不产生新值而是用于产生一个副作用(网络请求/日志打印/更新UI)等时,需要使用autorun

  • 要点:
    computed(function) 创建的函数只有当它有自己的观察者时才会重新计算,否则它的值会被认为是不相关的。而autorun创建后会立即运行一次;

  • 用法
    第一个参数一般为函数(如果是字符串,将被用作调试名),第二个参数为可选的对象参数,包括属性:delay(去抖时间)/name(reaction名称)/onError(处理reaction错误)/scheduler(设置自定义调度器决定autorun函数如何重新运行)

    autorun(() => {xxx
    }, { delay: 200 })
    

3. reaction——自定义反应

  • 含义:可以将reaction看作是autorun的变种,为`observable的追踪提供了更加细粒度的控制;

  • 用法:
    第一个为数据追踪函数,第二个为副作用函数(其中的任何observable都不会被追踪);第三个为可选的对象参数;
    只用在数据追踪函数返回新值时副作用函数才会运行;

    reaction(() => data, (data, reaction) => { sideEffect }, options?)
    
  • demo:

    // 只调用一次并清理掉 reaction : 对 observable 值作出反应。
    const reaction3 = reaction(() => counter.count,(count, reaction) => {console.log("reaction 3: invoked. counter.count = " + count);reaction.dispose();}
    );counter.count = 1;
    // 输出:
    // reaction 3: invoked. counter.count = 1counter.count = 2;
    // 输出:
    // (There are no logging, because of reaction disposed. But, counter continue reaction)
    

4. @observer——函数装饰器

  • 含义:可以将React组件转为响应式组件,响应被观察对象的改变;

  • 要点:它用 mobx.autorun 包装了组件的 render 函数以确保任何组件渲染中使用的数据变化时都可以强制刷新组件

  • 用法:

    当 observer 需要组合其它装饰器或高阶组件时,请确保 observer 是最深处(第一个应用)的装饰器,否则它可能什么都不做。

    observer(class Demo ... { })@observer class Demo extends React.Component {...
    }const Demo = observer(({ data }) =><span>type: { data.type } </span>
    );
    

5. 使用 inject 将组件连接到提供的 stores

import { observer, inject} from 'mobx-react';
import React from 'react';@inject('store')
@observer
class Casual extends React.Component {render() {return (<div><h2>num: {this.props.store.num}</h2><button onClick={this.handleClick}>increment</button></div>)}handleClick = () => {this.props.store.increment();}
}export default Casual;// store.js
import { action, observable, computed, decorate } from 'mobx';class Store {@observable num = 0;@computed get retNum() {return `the value of num is ${this.num}`} @action.boundincrement() {this.num++;}
}export default Store;

6. componentWillReact

  1. 含义:当组件因为它观察的数据发生重新渲染时,会触发该生命周期函数;可以追溯渲染并找到导致渲染的操作

  2. 要点:componentWillReact不接受任何参数;初始化渲染时不会被触发;

    @observer 以和 PureComponent 同样的方式实现了 shouldComponentUpdate,因此子组件可以避免不必要的重新渲染

  3. demo:

    import {observer} from "mobx-react";@observer class TodoView extends React.Component {componentWillReact() {console.log("I will re-render, since the todo has changed!");}render() {return <div>this.props.todo.title</div>;}
    }
    

Mobx API —— 改变observables

1. action

  • 含义:用于修改状态;

  • 用法

    action(fn)
    action(name, fn)
    @action classMethod() {}
    @action(name) classMethod() {}
    // @action.bound可以自动绑定到目标对象(即指定了this作用域)
    @action.bound classMethod() {} 
    ...
    
  • action.bound不要和箭头函数一起使用;


参考文献

  1. mobx中文文档
  2. Ten minute introduction to MobX and React
  3. Redux vs MobX without Confusion
  4. Becoming fully reactive: an in-depth explanation of MobX
  5. 为什么 Redux 需要不变性?
  6. Redux 是如何使用浅比较的?


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部