这篇帖子介绍 react mobx状态库的基本使用 。 注意,我用的版本是最新的 mobx v6,查看官网。
之前的版本是有装饰器这么一说,但这个装饰器是为了配合 class 组件,现在全面拥抱 hook 函数式组件,所以不推荐使用装饰器来定义 store 了。
笑死,说是这么说,但是store本身还是用的class来写的,但是现在有两个 API 来配置或者自动配置store。
他们分别是 makeObservable 和 makeAutoObservable,
他们需要在 class 中的 constructor 构造函数 中使用。
先来定义一个小车车看下怎么写的。
/src/mobx/cart.ts
import { action, computed, makeObservable, makeAutoObservable, observable } from "mobx";
type listType = Array<number | null>
class Cart {
list: listType = [];
constructor() {
makeObservable(this, {
list: observable,
getList: computed,
joinList: action,
});
// makeAutoObservable(this)
}
joinList(n: number) {
// this.list = [...this.list, n];
this.list.push(n);
}
reset() {
this.list.length = 0;
}
get getList() {
return this.list;
}
}
export default new Cart();
/src/mobx/index.ts
import { useContext } from "react";
import { createContext } from "react";
import Cart from "./cart";
class RootStore {
CartStore = Cart;
}
const store = new RootStore();
const AppStore = createContext(store);
export const useAppStore = () => {
return useContext(AppStore);
};
/src/page/TestMobx2.tsx
import { useAppStore } from "@/mobx";
import { observer } from "mobx-react-lite";
// observer: 监控当前组件使用到的由 MobX 跟踪的 observable state, 当状态发生变化时通知 React 更新视图
const Child_1 = () => {
const { CartStore } = useAppStore();
return (
<div>
<p>Child_1</p>
<button onClick={() => CartStore.joinList(CartStore.getList.length)}>添加</button>
<button onClick={() => CartStore.reset()}>清空</button>
</div>
);
}
const Child_2 = observer(() => {
const { CartStore } = useAppStore();
return (
<p>
<span>Child_2</span><br />
{CartStore.getList.map((i) => {
return <span key={i}>{i}、</span>;
})}
</p>
);
});
function MainTestBoxAll() {
// 调用 Counter 组件并传入管理其状态的 Store
return (
<>
<Child_1></Child_1>
<Child_2></Child_2>
</>
);
}
export default MainTestBoxAll;
上面我创建了一个store,并且用一个react上下文导出去,在页面上使用他们。
目前是这样的状态。
当我点击添加按钮时,一个新的数据通过 joinList 方法 被填入 list 中。
我点了三下,每次都把数组当前的length传入,但事实上现在 list 的length是3了。
在 Cart class中 我们写入了一个数据(list)和三个方法 (joinList,reset,getList)
makeObservable的第一个值绑定 这个类的this,第二个值绑定要导出的数据和方法,第三个值就是一些配置。
但是我没有在makeObservable中导出 reset 方法,那么点击清空会有用吗
虽然数据被清理了,但是mobx报了一个警告,虽然reset是在store里的方法,但是他没有被显示的导出去。
那其实可以用makeAutoObservable自动绑定偷一下懒
makeAutoObservable 他会自动导出你里面的方法,当然第二个参数可以写你不需要导出的方法。
makeAutoObservable(this,{
reset: false
})
造孽的又是 reset。
这样点清空后又开始发警告了。
还有一点要注意,如果想要使用 store 里的数据进行视图更新,那么一定要在这个组件外部包裹一个
observer。
如果不使用observer包裹组件,那么这个组件是不会有视图更新的。
const Child_2 = () => {
const { CartStore } = useAppStore();
return (
<p>
<span>Child_2</span><br />
{CartStore.getList.map((i) => {
return <span key={i}>{i}、</span>;
})}
</p>
);
};
joinList(n: number) {
this.list.push(n);
console.log([...this.list]);
}
我们打印出来的 list 数据是已经被添加了,但是Child_2并没有进行视图更新。
忘了加个异步处理了。
class Cart 里加一个方法
async witeReset() {
console.log('等待两秒');
await new Promise((res)=> setTimeout(()=> res(undefined), 2000))
this.reset();
console.log('清空完了');
}
Child_1
const Child_1 = () => {
const { CartStore } = useAppStore();
return (
<div>
<p>Child_1</p>
<button onClick={() => CartStore.joinList(CartStore.getList.length)}>添加</button>
<button onClick={() => CartStore.reset()}>清空</button>
<button onClick={() => CartStore.witeReset()}>异步清空</button>
</div>
);
};
可以看到它也是支持异步调用的。当然如果怕this指向有问题可以这样写。
makeObservable(this, {
list: observable,
getList: computed,
joinList: action,
reset: action,
witeReset: action.bound
});
// 或者
makeObservable(this, {
list: observable,
getList: computed,
joinList: action,
reset: action,
witeReset: action
},{
autoBind:true
});
// 或者
makeAutoObservable(this,{},{
autoBind:true
})
好了,这就是mobx的基本使用了,mobx还有很多东西在官网里,有兴趣的可以去看看。