运行机制
1、单向数据流
2、带副作用(比如网络请求,日志等)的数据流
3、由于UI和副作用处理器干的事情很像,它们都会接收状态的通知,最后通过Actions来变更状态,所以可以认为它们都是观察者,它们在观察状态,一旦状态发生了改变,它们会做出一些相应的响应最后简化图为:
| 概念 | 简述 | 通常指代对象 |
|---|---|---|
| observables | 状态 | 是可以被观察到变化的对象 |
| observers | 观察者 | UI和副作用 |
| actions | 事件行为 | 发送的消息、通知等 |
跨组件交互
<div>
<Main store={newState} />
<AllNum store={newState} />
</div>
2、那如果组件树比较深怎么办呢? React15版本的新特性context,它可以将父组件中的值传递到任意层级深度的子组件中。
@observer
@observable
1、React组件中可以直接添加@observable修饰的变量
autorun
1、状态发生变化时自动执行,使用其返回值函数可以将其注销掉数。不在autorun内被监听的状态发生变化时,不会导致autorun的触发
import {
observable, action, computed, autorun,
} from 'mobx';
export default class CycleLoanWithdrawStore {
@observable testV = 0;
@action testValue() {
this.testV += 1;
// this.currentLoanPeriod += 1;
}
constructor() {
autorun(() => console.log(this.testV));
}
}
2、同样可以放到@observer的UI的constructor中
import {autorun} from "mobx";
@observer
export default class XXComponent extends React.Component {
constructor(props) {
super(props);
this.store = new XXComponentStore();
autorun(() => console.log(this.store.testV));
}
observers的reactions(autorun、reaction、when)使用判断
- 判断副作用是否需要执行多次,只需要执行一次使用when
- 需要执行多次,每次依赖更新都要执行就使用autorun
- 需要执行多次,需要对依赖做进一步处理再决定做不做后续的处理则用reaction
ReactNative中MobX的实践示例
MobX with React Native, Simplified
mobx-react 渲染性能优化原理
- 该文有说道使用mobx后,mobx会为react组件提供一个精确的、细粒度的shouldComponentUpdate函数,所以理论上不在需要手动处理shouldComponentUpdate函数
- mobx提供的transaction功能,能够将多个observables的变更打包成一个事务,减少渲染次数【建议直接使用action,因为action内部就是使用transaction的】
import {observable, action, computed, autorun, transaction} from 'mobx';
export default class TestStore {
constructor() {
autorun(() => {
console.log(this.numbers.length, 'numbers!');
// 只会打印一次,最终的结果: 3 "numbers!"
});
}
@observable numbers = [];
change() { // 未使用action时
transaction(() => {
this.numbers.push(1);
this.numbers.push(2);
transaction(() => {
this.numbers.push(3);
})
})
}
}
...
// 在检测组件中调用TestStore的change方法
runInAction 使用例子
// 监测响应组件
@observer
export default class TestComponet extends React.Component {
constructor(props) {
super(props);
this.store = new TestStore();
}
render() {
console.log('render');
return (
<View style={{
flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'red',
}}>
<Text style={{ fontSize: 20 }} >{this.store.firstName}</Text>
<Text style={{ fontSize: 20 }} >{this.store.lastName}</Text>
<Text style={{ fontSize: 15, borderWidth: 1, borderColor: 'black' }}
onPress={() => this.store.change()}
>
change btn
</Text>
</View>
);
}
}
// store observable 组件
import {observable, action, computed, runInAction} from 'mobx';
export default class TestStore {
@observable firstName = '';
@observable lastName = '';
@action async change() {
const res = await new Promise((resolve, reject) => {
setTimeout(() => resolve({ code: '200100' }), 2000);
});
console.log('start - setTimeout');
setTimeout(() => {
// 这里会触发检测组件的render函数2次
// this.firstName = res.code;
// this.lastName = `测试用${(Math.random() * 1000).toFixed(2)} `;
// log:
// start - setTimeout
// render
// render
// end - setTimeout
// 只会触发检测组件的render函数1次
runInAction(() => {
this.firstName = res.code;
this.lastName = `测试用${(Math.random() * 1000).toFixed(2)} `;
})
console.log('end - setTimeout');
}, 2000);
// log:
// start - setTimeout
// render
// end - setTimeout
}
}
- 异步后的回调同样会多次触发render,失去action原有transaction效果
// ...
@action async change() {
const res = await new Promise((resolve, reject) => {
setTimeout(() => resolve({ code: '200100' }), 2000);
});
console.log('after await');
this.firstName = res.code;
this.lastName = `测试用${(Math.random() * 1000).toFixed(2)} `;
console.log('end change');
}
// ...
// log:
// after await
// render
// render
// end change
- runInAction后的恢复action原有transaction效果
// ...
@action async change() {
const res = await new Promise((resolve, reject) => {
setTimeout(() => resolve({ code: '200100' }), 2000);
});
console.log('after await');
runInAction(() => {
this.firstName = res.code;
this.lastName = `测试用${(Math.random() * 1000).toFixed(2)} `;
});
console.log('end change');
}
// ...
// log:
// after await
// render
// end change