理念
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数据流是单向的:
在整个数据流中,通过事件驱动(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
@observer
是mobx-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 (
....
);
}
}
@computed
其语法为:
@computed get computesValue [function];
例子看下面
@action
@action
,其规定对于 store 对象中所有可观察状态属性的改变都应该在 @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
函数之中,外加只需要调用该函数即可。
运行观察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中