Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

理解和学习mobx-react #19

Open
hawx1993 opened this issue Sep 8, 2017 · 0 comments
Open

理解和学习mobx-react #19

hawx1993 opened this issue Sep 8, 2017 · 0 comments
Labels

Comments

@hawx1993
Copy link
Owner

hawx1993 commented Sep 8, 2017

理念

MobX 是一个非常优雅的状态管理库,它的理念是通过观察者模式对数据做出追踪处理,在对可观察属性的作出变更或者引用的时候,触发其依赖的监听函数。这一点和Vue通过Object.defineProperty ,在对状态进行读写操作的时候会触发其 getter 和 setter 函数以进行响应的原理其实是非常类似的。

对于 React,你只需增加 observer 装饰器,即可将你的无状态组件转换为可响应组件:

const { observable, action, autorun } = require('mobx');

class Store {
    count = 0;
    @action add () {
        this.count = ++this.count;
    }
}
const mstore = new Store();
setInterval(() => {
    mstore.add();
}, 800);
autorun(() => {
    console.log(mstore.count);
});

在该例子中使用 autorun 的时候调用了一次其传入的函数,之后 mstore.count 的值即使改变也并没有触发观察,这是因为 mstore.count 并不是可观察的。这时,只需加一个@observable count = 0;将其设为可观察,即可对相应的值的变化做出相应的动作.
Mobx数据流是单向的:
image

在整个数据流中,通过事件驱动(UI 事件、网络请求…)触发 Actions,在 Actions 中修改了 State 中的值,这里的 State 即应用中的 store 树(存储数据),然后根据新的 State 中的数据计算出所需要的计算属性(computed values)值,最后响应(react)到 UI 视图层。

@observable

observable 的属性值在其变化的时候 ,mobx 会自动追踪并作出响应。其语法为:

import {observable} from "mobx";
import { observer } from "mobx-react";
@observable  classProperty = value

其核心原理是 Object.defineProperty ,给被包装的属性套上 getter 和 setter 的钩子,在 get 中响应依赖收集,在 set 中触发监听函数。

@observer

@observermobx-react提供的,通过使用@observer,将react组件转换成一个监听者,这样在被监听的应用状态变量(Observable)有更新时,react组件就会重新渲染。当 render 中的 state发生改变时, mobx-react 会重新调用 render 方法,重新渲染这个组件。如下
,TodoItemModel中的应用状态变量有更新时,TodoItem UI会重新渲染:

class TodoItemModel {
    id
    @observable title;
    @observable completed;
    ......
}

@observer
class TodoItem extends React.Component {
    .....
    render() {
        //UI logic code ...
        let todo = this.props.todo;
        let title = todo.title;
        let complete = todo.completed;
        return (
            ....
        );
    }
}

observer通过es7的装饰器模式,将一个React组件作为参数,并将其转为响应式(Reactive)组件。

@computed

其语法为:

@computed get computesValue [function]

例子看下面👇

@action

@action是mobx提供的,其规定对于 store 对象中所有可观察状态属性的改变都应该在 @action 中完成,凡是涉及到对应用状态变量修改的函数,都应该使用@action修饰符。从上图也可以看出,action会触发状态的改变:

语法形式:@action actionFuncName[function]

例子:

const { observable, action, computed, autorun } = require('mobx');

class Store {
    @observable list = []
    @computed get total() {
        return this.list.length;
    }
   @action change (i) {
        this.list.push(i++);
    }
}
const mstore = new Store();
autorun(() => {
    console.log(mstore.total);
});
mstore.change(1)

可以看到,store 中 list 属性的改变都放在 @action change 函数之中,外加只需要调用该函数即可。
所有对可观察数据地修改,都应该在 action 中进行,不然容易导致状态婚乱,难以管理。

运行观察autorun

autorun用来包装一个方法为 观察者。
在上面的例子中,当触发了可观察状态属性的改变后,其变化的监听则是在传入 autorun 函数中作出响应。

autorun传入一个函数,当该函数中依赖的可观察状态属性(或者计算属性)发生变化的时候,该函数会被调用。这个函数只会观察自己依赖到的设为 observable 的值。

class Store {
    @observable count = 0;
    @action add () {
        this.count = this.count + 1;
    }
}
const mstore = new Store();
var sId = setInterval(() => {
    mstore.add();
}, 2000);

autorun(() => {
    if(mstore.count >2){
        clearInterval(sId)
    }
    console.log(mstore.count);
});

autorun 的函数依赖了 mstore.count 属性,该属性是可观察的,其每次变化都会加 1 ,因此其中的函数在第一次立即触发,之后每次改变 mstore.count 的值都会被触发;当该为大于2时,清空了定时器,该值不再变化,autorun函数也不再触发

Provider组件

在react中,mobx-react提供了 Provider 组件用来包裹最外层组件节点,并且传入 store(通过)context 传递给后代组件:

import { Provider } from 'mobx-react';
const stores = {
  ...
};
ReactDOM.render((
  <Provider {...stores}>
    <App />
  </Provider>
), document.getElementById('root'));

@Inject

@inject 是为了向当前被装饰的组件 注入 store 这个props。当然 store 这个 prop 其实是由 Provider 提供的

配置

在react中,通过.babelrc即可配置es7的装饰器语法:

{
  "presets": [
    "es2015",
    "stage-1",
    "react"
  ],
  "plugins": ["transform-decorators-legacy"]
}

当然,你需要

$ npm i babel-preset-{es2015,stage-1,react} babel-plugin-transform-decorators-legacy

对于NodeV5以上版本,无需--save就会自动帮你安装到dependencies中

对于decorators,如果你使用create-react-app创建项目, 需要:

$ npm i babel-preset-stage-2 babel-preset-react-native-stage-0 --save-dev

然后在babelrc文件中输入:

{
  "presets": ["react-native-stage-0/decorator-support"]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant