安装
yarn add mobx
yarn add mobx-react-lite
核心概念
- observable 定义一个存储 state 的可追踪字段。
- action 将一个方法标记为可以修改 state 的 action。
- computed 标记一个可以由 state 派生出新的值并且缓存其输出的 getter。
- reactions 函数接受两个函数作为参数,第一个函数返回一个要监听的对象,每当该函数所观察的值发生变化时,第二个函数都执行。
工作流程
例子1
1.定义store
import { action, makeObservable, observable } from 'mobx';
//makeObservable
//参数一:需要监听哪个对象
//参数二:需要监听对象中的哪些属性
class Count {
count = 0;
constructor() {
makeObservable(this, {
count: observable, //将count定义成state字段
increment: action.bound, //将函数定义为修改state 的 action。 // bound为了绑定this否则外面只能用建有函数来调用方法
reset: action.bound //将函数定义为修改state 的 action。 // bound为了绑定this否则外面只能用建有函数来调用方法
double: computed //将函数定义成计算属性
});
}
increment() {
this.count += 1;
}
reset() {
this.count = 0;
}
get double() { //计算属性前面要加上get
return this.count * 2;
}
}
export default new Count(); //应导出一个实例对象而不是类
2.组件内使用
import React, {} from 'react';
import { observer } from 'mobx-react-lite'; //mobx-react-lite Or "mobx-react" 后者兼容class组件,体积更大
import count from '../store/count';
const Test:React.FC<{}> = () => {
return (
<>
<div>test</div>
<div>次数:{count.count}</div>
<button onClick={() => count.increment()}>加一</button>
<button onClick={() => count.increment()}>加一</button>
<button onClick={() => count.reset()}>重置</button>
//注意:如果store定义时没有绑定this,这种形式调用将报错,因为this指向了window
<button onClick={count.increment}>加一</button>
</>
);
};
export default observer(Test);
3.makeAutoObservable
的使用
是一个加强版的makeObservable
可以自动推算属性,不用手动指定类型了
eg:
- 所有的属性推断为observable
- 所有的方法为action
- 所有的get为computed
import {
makeAutoObservable
} from 'mobx';
// makeAutoObservable
// 第一个参数指定要监视的对象
// 第二个参数指定不要监视对象中的哪些属性
// 第三个参数绑定this
class Count {
count = 0;
constructor() {
makeAutoObservable(this, { reset: false }, { autoBind: true });
}
increment() {
this.count += 1;
}
reset() {
this.count = 0;
}
get double() {
return this.count * 2;
}
}
export default new Count();
autoRun
和Reaction
监视具体的某个属性
1.autoRun
只要监听的属性有变化就会执行包括第一次加载
import {
autorun,
makeAutoObservable
} from 'mobx';
class Count {
count = 0;
constructor() {
makeAutoObservable(this, { reset: false }, { autoBind: true });
}
increment() {
this.count += 1;
}
reset() {
this.count = 0;
}
get double() {
return this.count * 2;
}
}
const count = new Count();
// 只要count.count有变化就会执行包括第一次加载
autorun(() => {
console.log(count.count);
});
export default count;
2.reaction
更加精细的监控,第一次渲染不执行
接受两个参数
第一个参数的返回值返回要监听的对象的某个属性
第二个函数将根据第一个函数返回的属性值发生变化将执行第二个函数,并且接受新值和旧值两个参数
reaction(() => count.count, (value, oldValue) => {
console.log(value, oldValue);
});
异步处理 runInAction()
接受一个会回调
数据的修改应在action里面修改否则会报警告
import {
autorun,
makeAutoObservable, reaction, runInAction,configure
} from 'mobx';
configure({
enforceActions: 'observed' //配置这个可以消除警告但是不建议使用
});
import {
autorun,
makeAutoObservable, reaction, runInAction
} from 'mobx';
// makeAutoObservable
// 第一个参数指定要监视的对象
// 第二个参数指定不要监视对象中的哪些属性
// 第三个参数绑定this
class Count {
count = 0;
constructor() {
makeAutoObservable(this, { reset: false }, { autoBind: true });
}
async increment() {
const res =await axios.get<Count>("/count")
runInAction(()=>{ // async函数里面直接修改属性值会报错,一次要用到runInAction
this.count += res;
})
}
reset() {
this.count = 0;
}
decrement() {
setTimeout(() => {
runInAction(() => { // setTimeout函数里面直接修改属性值会报错,一次要用到runInAction
this.count -= 1;
});
},2000);
}
get double() {
return this.count * 2;
}
}
const count = new Count();
reaction(() => count.count, (value, oldValue) => {
console.log(value, oldValue);
});
export default count;
模块化
import { createContext, useContext } from 'react';
import count from './count';
import auth from './auth';
class RootStore {
count = count;
auth = auth;
}
const store = new RootStore();
// 创建一个上下文
const Context = createContext(store);
// 自定义一个hook使用这个上下文
export default function useStore() {
return useContext(Context); //不用上下文也可以只不过这样更加规范
}
组件内使用
import React, {} from 'react';
import { observer } from 'mobx-react-lite';
import useStore from '../store';
const Test:React.FC<{}> = () => {
const { count ,auth } = useStore(); //解构获取两个store
return (
<>
<div>test</div>
<div>作者:{auth.username}</div>
<div>次数:{count.count}</div>
<div>计算:{count.double}</div>
<button onClick={() => count.increment()}>加一</button>
<button onClick={() => count.decrement()}>异步减一</button>
<button onClick={() => count.reset()}>重置</button>
</>
);
};
export default observer(Test);