mobx简介

2018-03-08  本文已影响0人  boyrt

官方文档-传送

MobX是响应式编程,实现状态的存储和管理。使用MobX将应用变成响应式可归纳为三部曲:

  1. 定义状态并使其可观察
  2. 创建视图以响应状态的变化
  3. 更改状态

在介绍这三个步骤之前,我们先了解下MobX的核心API。

一、MobX核心API

1. Observable

observable是将类属性等进行标记,实现对其的观察。三部曲中的第一曲,就是通过Observable实现的。

observable
创建observable的方式很多,推荐使用ES7的装饰器(@observable),如何开启装饰器,后面将会介绍。
observable的value值的类型参照上图,observable包装后返回对应类型的值,如Observable Object等。

2. Actions

动作,通过action改变state。三部曲中的第一曲通过action创建一个动作。action函数是对传入的function进行一次包装,使得function中的observable对象的变化能够被观察到,从而触发相应的衍生。

action

3. 衍生

对observable的响应。三部曲中的第二部的实现方式。

衍生

衍生主要分为Reactions和Computed values。其中reactions是自动响应状态变化的副作用,如UI变化、控制台输出、后台服务传送数据。而Computed values(计算值)是自动响应状态变化的值。

4. Decorators

装饰器,可使用的装饰器列表

observable.deep
observable.ref
observable.shallow
computed
action
action.bound

可以使用 @decorator 语法来应用这些装饰器。

[官方文档说明]

5. FLOW

创建异步action的一种方式,这里不介绍了。官网传送

二、 开启装饰器(Decorators)

(1)添加装饰器依赖:babel-plugin-transform-decorators-legacy
(2).babelrc文件添加配置

"plugins": ["transform-decorators-legacy"]

三、三部曲

通过一个小demo,讲述如何使用MobX将应该用变成响应式。

首先必须先添加mobx和mobx-react依赖,装饰器依赖根据用户选择添加。

1. 第一曲

定义状态并使其可观察

新建mobx文件夹,observable的相关.js文件存储在此,如下图所示:

image.png

如何定义状态,并使得其可观察呢?接着看代码:
counter_store.js(计数):

import { observable } from 'mobx'

class CounterStore {
    @observable counter = 0;
    @observable remoteCounter = 0;

    constructor(){}

increment(){
        this.counter++;
    }

    decrement(){
        this.counter--;
    }

    incrementAsync(){
        setTimeout(()=>{
            this.counter++
        },500);
    }
}

const counterStore = new CounterStore;

export default counterStore;

CounterStroe类中,对counter、remoteCounter使用了observable装饰器,即将counter、remoteCounter定义为MobX的状态,并可观察。

虽然increment、decrement、incrementAsync函数前无@action,但是因为没有设置强制action,所以默认被action装饰,都是创建了一个动作。

2. 第二曲

创建视图以响应状态的变化

首先使用observer包裹React组件的高级组件:

@observer
export default class HomeScreen extends Component {
  ...
}

其次,在HomeScreen组件的render方法中,使用被observable转换的值。

import counterStore from '../../mobx/counter_store'

    render() {
        return (
            <View style={styles.container}>
                <Text>Counter Container Test</Text>
                <Text>Clicked:<Text>{`${counterStore.counter}times`}</Text></Text>
                <Text onPress={()=>counterStore.increment()}>| +1 |</Text>
                <Text onPress={()=>counterStore.incrementAsync()}>| +1 Async |</Text>
            </View>
        );
    }
}

3. 第三曲

更改状态

在CounterStore类中,通过action创建了三个动作,分别是increment、decrement、incrementAsync。通过调用action装饰过的函数,实现更改状态的目的。
请看代码,onPress事件中调用函数:

import counterStore from '../../mobx/counter_store'

    render() {
        return (
            <View style={styles.container}>
                <Text>Counter Container Test</Text>
                <Text>Clicked:<Text>{`${counterStore.counter}times`}</Text></Text>

                <Text onPress={()=>counterStore.increment()}>| +1 |</Text>
                <Text onPress={()=>counterStore.incrementAsync()}>| +1 Async |</Text>
            </View>
        );
    }
}

当点击‘+1’时,上面的次数显示会响应的变化。这就是所谓的副作用一种形式。

拓展

如何进行状态的引用呢?

两种方式:

  • 全局注册并注入store实例
  • 直接import引用

全局注册并注入store
我参考的demo:https://juejin.im/post/5a3f06cd6fb9a044fe4693bc
demo中使用了Provider进行全局注册并注入Rootstore实例

const Navigation = () => {
    return (
        <Provider rootStore={store}>
            <Navigator/>
        </Provider>
    )
}

在需要使用的组件中,使用@inject('rootStore') ,我们就可以愉快地使用 this.props.rootStore 来拿到我们想要的数据啦

@inject('rootStore')
@observer
export default class HomeScreen extends Component {
  ...
}

注:@observer也需要添加,不然不会随着rootStore属性变化而重新渲染。

直接import引用
不进行全局注册,而是在需要使用mobx的Rootstore实例的组件中进行引用即可。

import counterStore from '../../mobx/counter_store'

Github项目demo

上一篇 下一篇

猜你喜欢

热点阅读