博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mobx 我的理解
阅读量:4086 次
发布时间:2019-05-25

本文共 7275 字,大约阅读时间需要 24 分钟。

什么是MobX

官方图

 

image.png

 

网图

 

安装

1.安装MobX:yarn add mobx --save

2.安装React绑定库:yarn add mobx-react --save

3.启用装饰器语法(能够使用@标签)

第一步:

yarn add babel-plugin-transform-decorators-legacy babel-preset-react-native-stage-0 --save-dev

第二步:在.babelrc文件中修改为

{  "presets": ["react-native"],  "plugins": ["transform-decorators-legacy"]}

MobX常用标签

@observable : 使用此标签监控要检测的数据; @observer: 使用此标签监控当数据变化是要更新的Component(组件类) autorun : 当观测到的数据发生变化的时候,如果变化的值处在autorun中,那么autorun就会自动执行。 @action : 使用此标签监控数据改变的自定义方法(当在需要数据改变的时候执行此自定义方法,那么View层也会跟着自动变化,默认此View层已经使用@observer标签监控) useStrict : 使用严格模式 @computed : 计算值(computed values)是可以根据现有的状态或其它计算值衍生出的值,可以定义在相关数据发生变化时自动更新的值.

Observable

用法observable(value)或@observable classProperty = value

可以理解为被观察者对象,其值可以是JS基本数据类型、引用类型、普通对象、类实例、数组和映射。

注意:如果value是没有原型的对象(例如:{key: 'key', value: 'value'}普通对象是指不是使用构造函数创建出来的对象,而是以 Object 作为其原型,或者根本没有原型。 ),则该对象会被克隆,并且其所有的属性都会被转换为可观察的;如果value是有原型的对象(例如:new MyClass()),MobX 不会将一个有原型的对象自动转换成可观察的,在该类中的构造函数中使用extendObservable或在类定义上使用 @observable / decorate

对observable的变化做出响应

类似于Vue中的计算属性,根据现有被观察的对象计算衍生出新的值。

import {observable, computed} from "mobx"class Cart {    @observable price = 0;    @observable amount = 1;    constructor(price) {        this.price = price;    }    @computed get total() {        return this.price * this.amount;    }}

若前一个计算中使用的数据没有更改,计算属性将不会重新运行;当其有观察者的时候才会重新计算;如果一个计算属性不在被观察了(使用它的UI被销毁了),Mobx会自动将其回收。

2.autorun

不需要被观察者观察,创建的时候被触发一次,然后每次它的依赖关系改变时会再次被触发 ,常用作打印日志,更新UI等。 autorun 中的值必须要手动清理才行 ,传递给 autorun 的函数在调用后将接收一个参数,即当前 reaction(autorun),可用于在执行期间清理 autorun

var numbers = observable([1,2,3]);var sum = computed(() => numbers.reduce((a, b) => a + b, 0));var disposer = autorun(() => console.log(sum.get()));// 输出 '6'numbers.push(4);// 输出 '10'// 清理autorun disposer();numbers.push(5);// 不会再输出任何值。`sum` 不会再重新计算。

3.observer

observer 是由单独的 mobx-react 包提供的 ,observer 函数/装饰器可以用来将 React 组件转变成响应式组件

import {  observable,  computed,  autorun,  action} from 'mobx'class AppState {  @observable timer = 0  // 注意这里不能调用super(props),否则报错  constructor (props) {    setInterval(() => {      this.timerIncreat(this.timer)    }, 1000)  }  @action timerIncreat (time) {    this.timer = time += 1  }  // 重置计数器  @action resetTimer () {    this.timer = 0  }}export default AppState
import React, {Component} from 'react'import {View, StyleSheet} from 'react-native'import {Button, Label} from 'teaset'import AppState from '../mobx/AppState'import { observer } from 'mobx-react'// 实例化,也可在导出的时候实例化const appState = new AppState()// 这里必须要写,不然监听不到值的变化@observerexport default class MobxDemo1 extends Component {  static navigationOptions = ({navigation, screenProps}) => ({      headerTitle: 'Mobx练习一'  })  render () {    return (      

改变observable的值

  1. action

顾名思义就是动作,所有被观察的对象被修改都应该通过动作函数来进行修改

用法有以下几种:action(fn)action(name, fn)@action classMethod() {}@action(name) classMethod () {}@action boundClassMethod = (args) => { body }@action(name) boundClassMethod = (args) => { body }@action.bound classMethod() {}

2.异步action

action只能影响正在运行的函数,而无法影响当前函数调用的异步操作 。action 包装/装饰器只会对当前运行的函数作出反应,而不会对当前运行函数所调用的函数(不包含在当前函数之内)作出反应 ,也就是说promise的then或async语句,并且在回调函数中某些状态改变了,这些回调函数也应该包装在action中。
(1)第一种方案,使用action关键字来包装promises的回调函数。
// 第一种写法

class Store {@observable githubProjects = []@observable state = "pending" // "pending" / "done" / "error"@actionfetchProjects() {    this.githubProjects = []    this.state = "pending"    fetchGithubProjectsSomehow().then(        // 内联创建的动作        action("fetchSuccess", projects => {            const filteredProjects = somePreprocessing(projects)            this.githubProjects = filteredProjects            this.state = "done"        }),        // 内联创建的动作        action("fetchError", error => {            this.state = "error"        })    ) }}

// 第二种写法

class Store {     @observable githubProjects = []     @observable state = "pending" // "pending" / "done" / "error"     @action     fetchProjects() {         this.githubProjects = []         this.state = "pending"         fetchGithubProjectsSomehow().then(             projects => {                 const filteredProjects = somePreprocessing(projects)                 // 将修改放入一个异步动作中                 runInAction(() => {                     this.githubProjects = filteredProjects                     this.state = "done"                  })             },             error => {                 runInAction(() => {                     this.state = "error"                 })             }         )     } }

第二种方案,用async function来处理业务,那么我们可以使用runInAction这个API来解决之前的问题 。

import {observable, action, useStrict, runInAction} from 'mobx';useStrict(true);class Store {  @observable name = '';  @action load = async () => {    const data = await getData();    // await之后,修改状态需要动作    runInAction(() => {      this.name = data.name;    });  }}
  1. flows
    然而,更好的方式是使用 flow 的内置概念。它们使用生成器。一开始可能看起来很不适应,但它的工作原理与 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"        }    })}

实际中的运用

跨组件交互

在不使用其它框架、类库的情况下,React要实现跨组件交互这一功能相对有些繁琐。通常我们需要在父组件上定义一个state和一个修改该state的函数。然后把state和这个函数分别传到两个子组件里,在逻辑简单,且子组件很少的时候可能还好,但当业务复杂起来后,这么写就非常繁琐,且难以维护。而用Mobx就可以很好地解决这个问题。来看看以下的例子:

class MyState {  @observable num1 = 0;  @observable num2 = 100;  @action addNum1 = () => {    this.num1 ++;  };  @action addNum2 = () => {    this.num2 ++;  };  @computed get total() {    return this.num1 + this.num2;  }}const newState = new MyState();const AllNum = observer((props) => 
num1 + num2 = {props.store.total}
);const Main = observer((props) => (

num1 = {props.store.num1}

num2 = {props.store.num2}

));@observerexport default class App extends React.Component { render() { return (
); }}

有两个子组件,Main和AllNum (均采用无状态函数的方式声明的组件)

在MyState中存放了这些组件要用到的所有状态和函数。
之后只要在父组件需要的地方实例化一个MyState对象,需要用到数据的子组件,只需要将这个实例化的对象通过props传下去就好了。

那如果组件树比较深怎么办呢?

我们可以借助React15版本的新特性context来完成。它可以将父组件中的值传递到任意层级深度的子组件中。
总结
Mobx想要入门上手可以说非常简单,只需要记住少量概念并可以完成许多基础业务了。但深入学习下去,也还是要接触许多概念的。例如Modifier、Transation等等。
最后与Redux做一个简单的对比

Mobx写法上更偏向于OOP

对一份数据直接进行修改操作,不需要始终返回一个新的数据
对typescript的支持更好一些
相关的中间件很少,逻辑层业务整合是一个问题

作者:水落斜阳
链接:https://www.jianshu.com/p/66dd328726d7
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

你可能感兴趣的文章
【Unity】Destroy和DestroyImmediate的区别
查看>>
【Lua】Mac系统下配置SublimeText的Lua编译环境
查看>>
【C#】利用Conditional属性完成编译忽略
查看>>
【Unity】微信登录后将头像存为bytes,将bytes读取成sprite图片
查看>>
【Unity】使用GPS定位经纬度
查看>>
【UGUI/NGUI】一键换Text/Label字体
查看>>
【C#】身份证本地验证
查看>>
【Unity】坑爹的Bug
查看>>
【算法】求数组中某两个数的和为目标值
查看>>
sql server如何编辑超过前200行的数据
查看>>
如何高效学习动态规划?
查看>>
动态规划法(六)鸡蛋掉落问题(一)
查看>>
LeetCode 887.鸡蛋掉落(C++)
查看>>
Dijkstra‘s algorithm (C++)
查看>>
奇异值分解(SVD)的原理详解及推导
查看>>
算法数据结构 思维导图学习系列(1)- 数据结构 8种数据结构 数组(Array)链表(Linked List)队列(Queue)栈(Stack)树(Tree)散列表(Hash)堆(Heap)图
查看>>
求LCA最近公共祖先的离线Tarjan算法_C++
查看>>
Leetcode 834. 树中距离之和 C++
查看>>
【机器学习】机器学习系统SysML 阅读表
查看>>
最小费用最大流 修改的dijkstra + Ford-Fulksonff算法
查看>>