Mobx
1、Mobx介绍
(1) Mobx是一个功能强大,上手非常容易的状态管理工具。
(2) Mobx背后的哲学很简单: 任何源自应用状态的东西都应该自动地获得。
(3) Mobx利用getter和setter来收集组件的数据依赖关系,从而在数据发生变化的时 候精确知道哪些组件需要重绘,在界面的规模变大的时候,往往会有很多细粒度更新。
(4)Mobx写法上更偏向于OOP 对一份数据直接进行修改操作,不需要始终返回一个新的数据 并非单一store,可以多store。
2、Mobx的优缺点
优点:
a. 学习成本小
b. 面向对象编程, 而且对 TS 友好
缺点:
a. 过于自由:Mobx提供的约定及模版代码很少,代码编写很自由,如果不做一些约 定,比较容易导致团队代码风格不统一
b. 相关的中间件很少,逻辑层业务整合是问题
3、Mobx的相关Api
(1)observable 和 autorun
observable 指定要观察的变量,对于常量使用observable.box()方式观察,对象数组可以直接使用observable()
autorun 当观察的变量变化后,会调用它的回调函数
import { observable, autorun } from 'mobx';
const value = observable.box(0);
const number = observable.box(100);
autorun(() => {
console.log(value.get());
});
value.set(1);
value.set(2);
number.set(101);
//0,1,2。 // autorun 使用到才能被执行
//只能是同步,异步需要处理
//观察对象,通过map
const map = observable.map({ key: "value"});
//map.set("key", "new value");
//map.get("key")
//观察对象,不通过map
const map = observable({ key: "value"});
// map.key map.key="xiaoming"
//观察数组
const list = observable([1, 2, 4]);
list[2] = 3;
(2) action和runInAction
action:在严格模式下必须使用anction 修饰的方法来修改observable包裹的变量
runInAction:它的执行时机是在下一个事件循环tick,即下一个Promise被resolve或reject后,
在严格模式下,异步数据操作需要用runInAction包裹,否则会导致状态更新不成功。
import {observable, action, configure,runInAction} from 'mobx';
configure({enforceActions:'always'})
//严格模式, 必须写action,
//如果是never,可以不写action,
//最好设置always, 防止任意地方修改值, 降低不确定性。
class Store {
@observable number = 0;
@observable name = "kerwin";
@action add = () => {
this.number++;
}//action只能影响正在运行的函数,而无法影响当前函数调用的异步操作
@action load = async () => {
const data = await getData();
runInAction(() => {
this.name = data.name;
});
}// runInAction 解决异步问题
}
const newStore = new Store();
newStore.add();
//如果在组件监听
componentDidMount() {
autorun(()=>{
console.log(newStore.number);
})
}
(3)when和reaction
when:在符合条件的时候才会执行回调函数,并且只会执行一次
import {observable, when} from 'mobx';
const count = observable.box(10)
when(count>11,()=>{console.log(count)})
setInterval(()=>{
count++
},1000)
reaction:与autorun类似,observable 包裹的变量变化后就会执行相关的回调,但是在初始的时候不会执行
import {
observable,
configure,
runInAction,
action,
reaction,
} from 'mobx';
configure({enforceActions:'always'})
class Store {
@observable number:number = 0;
@observable price:number = 0;
@observable amount:number = 0
@action updateNumberPrice = (num:number,price:number) => {
this.number = num
this.price = price
}
@action updateAmount = (newValue:number) => {
this.amount = newValue;
}
}
const store = new Store()
reaction([store.number,store.price],()=>{
const amount = store.number * store.price
store.updateAmount(amount)
})
4、mobx-react的使用
(1)react 组件里使用 @observer observer 函数/装饰器可以用来将 React 组件转变成响应式组件。
(2) 可观察的局部组件状态 @observable 装饰器在React组件上引入可观察属性。而不需要通过 React 的冗长和强制性的 setState 机制来管 理。
import {observer} from "mobx-react"
import {observable} from "mobx"
@observer class Timer extends React.Component {
@observable secondsPassed = 0
componentWillMount() {
setInterval(() => {
this.secondsPassed++
}, 1000)
}//如果是严格模式需要加上 @action 和 runInAction
//一个新的生命周期钩子函数 componentWillReact
//当组件因为它观察的数据发生了改变,它会安排重新渲染,
//这个时候 componentWillReact 会被触发
componentWillReact() {
console.log("I will re-render, since the todo has changed!");
}
render() {
return (<span>Seconds passed: { this.secondsPassed } </span> )
}
}
ReactDOM.render(<Timer />, document.body)
5、装饰器的配置
npm i @babel/core @babel/plugin-proposal-decorators @babel/preset-env
创建.babelrc
{
"presets": [
"@babel/preset-env"
],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
]
]
}
const path = require('path')
const { override, addDecoratorsLegacy } = require('customize-cra')
function resolve(dir) {
return path.join(__dirname, dir)
}
const customize = () => (config, env) => {
config.resolve.alias['@'] = resolve('src')
if (env === 'production') {
config.externals = {
'react': 'React',
'react-dom': 'ReactDOM'
}
}
return config
};
module.exports = override(addDecoratorsLegacy(), customize())
创建config-overrides.js
const path = require('path')
const { override, addDecoratorsLegacy } = require('customize-cra')
function resolve(dir) {
return path.join(__dirname, dir)
}
const customize = () => (config, env) => {
config.resolve.alias['@'] = resolve('src')
if (env === 'production') {
config.externals = {
'react': 'React',
'react-dom': 'ReactDOM'
}
}
return config
};
module.exports = override(addDecoratorsLegacy(), customize())
安装依赖
npm i customize-cra react-app-rewired
修改package.json
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
}