![](https://img.haomeiwen.com/i3666568/590d0e2f2e4621b5.png)
Mobx 数据管理模式,通过行为修改状态,然后更新到视图。
- Mobx 的写法
mobx 采用了ES7 语法的修饰器
function setAge(target){
target.age = 28;
}
@setAge
class Person {}
// 等同于
Person = setAge(Person) || Person;
console.log(Person.age);
利用装饰器代理函数使用起来更方便。 B格更高
- 常用的三个属性
observable 观察者
action 行为动作(唯一可以改变state)
computed 计算属性
const { observable, action, computed, autorun } = mobx;
class Store {
@observable list = []
// 自动执行
@computed get total() {
return this.list.length;
}
// 手动执行
@action change () {
this.list.push(this.list.length);
}
};
const mstore = new Store();
setInterval(() => {
mstore.change();
}, 2000);
autorun(() => {
console.log(mstore.total);
});
核心部分
- 可观察状态(State)
@observable 修饰器将其中的属性转变为可观察的状态值
@observable classProperty = value
@observable 接受任何类型的 js 值(原始类型、引用、纯对象、类实例、数组和、maps),observable 的属性值在其变化的时候 mobx 会自动追踪并作出响应。
调节器的配置:
@observable.deep (默认)对对象进行深拷贝;
@observable.shallow 它只对对象进行浅拷贝;
@observable.ref 禁用对象的自动转化,只转化其引用
@observable classProperty = { obj: { name: 'q' } }
当 value 是一个对象类型值的时候,它会默认克隆该对象并且把其中每个属性变为可观察的值,这里默认是深拷贝,也就是说其对象的后代属性都会变成可观察的,当 classProperty.obj.name 改变的时候,在 MobX 中也是可以观察到并响应的;
- 追加属性的观察
这时需要使用 extendObservable 来扩展对象
const { observable, action, computed, autorun, extendObservable } = mobx;
class Store {
@observable oo = {
name: 1
}
};
const mstore = new Store();
extendObservable(mstore, {
oo: {
age: 0
}
});
var i = 1;
setInterval(() => {
mstore.oo.age = i++;
}, 2000);
autorun(() => {
console.log(mstore.oo.age);
});
- 计算属性值(Computed Values)
是一类衍生值,它是根据现有的状态或者其他值计算而来。
两个原则:
1、计算属性中尽可能地不对当前状态做任何修改;
2、任何可以通过现有状态数据得到的值都应该通过计算属性获取。
@computed get computesValue [function];
- 动作(Action)
在 MobX 中,对于 store 对象中可观察的属性值,在他们改变的时候则会触发观察监听的函数,这里注意两点:
该属性必须是定义的可观察属性(@observable)
它的值必须发生改变(和原值是不等的)
class Store {
@observable list = []
@observable name = '2'
@observable oo = {
age: 1
}
};
const mstore = new Store();
// 触发观察监听的函数
mstore.list.push('1');
// 或者
mstore.name = 'h';
// 或者
mstore.oo.age = 12;
// 这个情况下是不会触发观察,因为 age 属性并不可观察
mstore.age = 10;
// 这个情况下也不会触发观察,因为其值没有发生变化
mstore.oo.age = 1;
存在异步行为,比如网络请求
import { observable, action } from "mobx";
import axios from "axios";
export default class Store {
@observable authenticated;
@observable authenticating;
@observable items;
@observable item;
@observable testval;
// 初始化 state
constructor() {
this.authenticated = false;
this.authenticating = false;
this.items = [];
this.item = {};
this.testval = "Hello";
}
async fetchData(pathname, id) {
let { data } = await axios.get(
`localhost:3000/${pathname}`
);
data.length > 0 ? this.setData(data) : this.setSingle(data);
}
@action setData(data) {
this.items = data;
}
@action setSingle(data) {
this.item = data;
}
@action clearItems() {
this.items = [];
this.item = {};
}
@action authenticate() {
return new Promise((resolve, reject) => {
this.authenticating = true;
setTimeout(action(() => {
this.authenticated = !this.authenticated;
this.authenticating = false;
resolve(this.authenticated);
}), 100);
});
}
}
- 运行观察(autorun)
在上面的例子中,当触发了可观察状态属性的改变后,其变化的监听则是在传入 autorun 函数中作出响应。
autorun 接受一个函数作为参数,在使用 autorun 的时候,该函数会被立即调用一次,之后当该函数中依赖的可观察状态属性(或者计算属性)发生变化的时候,该函数会被调用,注意,该函数的调用取决的函数中使用了哪些可观察状态属性(或者计算属性)。
React 中使用 MobX
在实际使用中,autorun 中的函数就是用来操作 Reactions 的,当可观察状态属性的值发生改变的时候,可以在该函数中利用状态值来更新改变 UI 视图(记录日志、持久化),在 MobX 结合 React 的使用中,mobx-react 库则是封装了 autorun 用来在 store 中的可观察状态属性值发生改变的时候 rerender React 组件。
核心
核心
@Provider
Provider 组件用来包裹最外层组件节点,并且传入 store(通过)context 传递给后代组件:
import { Provider } from 'mobx-react';
const stores = {
...
};
ReactDOM.render((
<Provider {...stores}>
<App />
</Provider>
), document.getElementById('root'));
@inject
@observer
@inject 给组件注入其需要的 store(利用 React context 机制);
@observer 将 React 组件转化成响应式组件,它用 mobx.autorun 包装了组件的 render 函数以确保任何组件渲染中使用的数据变化时都可以强制刷新组件:
import React from 'react';
import { inject, observer } from 'mobx-react';
@inject('userStore', 'commonStore')
@observer
export default class App extends React.Component {
componentWillMount() {
if (this.props.commonStore.token) {
this.props.userStore.pullUser()
.finally(() => this.props.commonStore.setAppLoaded());
} else {
this.props.commonStore.setAppLoaded();
}
}
render() {
if (this.props.commonStore.appLoaded) {
return (
<div>
...
{this.props.children}
</div>
);
}
return (
...
);
}
}
TIP:
在 mobx 中,可以有很多种方式去修改 state,mobx 并不对其做限制;
但是如果使用了严格模式:
import { useStrict } from 'mobx';
useStrict(true);
总结
MobX 的理念是通过观察者模式对数据做出追踪处理,在对可观察属性的作出变更或者引用的时候,触发其依赖的监听函数,在 React 中既是在 @observer 中对组件进行数据更新并渲染到视图层面,其核心与开发模式和 Vue 非常相似。
相比于 Redux 纯函数的形式,它在代码层面却是给开发者减少了不少工作量,但在多人维护的大项目中,个人认为还是 Redux 更加有利,一旦项目中的数据交互增多,其在 MobX 中对于数据流的变化就变得难以理清,而只能依靠约定来限制触发场景。
网友评论