原文链接
mobx-react@7.x hooks
前言
mobx-react@7.x
相较于mobx-react@6.x
有很大改变, api 也有所不同. 因此写法有改变. 另外本例子是基于react@17.0.1
+react hooks
+mobx@6.x
+ mobx-react@7.x
+ typescript
创建的.
如何定义子模块
mobx-react@7.x
提供了makeAutoObservable方法, 用来将普通对象转化为可观察对象.
官方文档的例子中是在constructor
中进行转化的.
// /src/store/timer.ts
class Timer {
secondsPassed = 0;
constructor() {
makeAutoObservable(this);
}
increaseTimer() {
this.secondsPassed += 1;
}
}
但是经过测试, 只需要最终引用的实例对象被转化即可
class Timer {
secondsPassed = 0;
increaseTimer() {
this.secondsPassed += 1;
}
}
const timer = makeAutoObservable(new Timer());
另外, 例子中的子模块类的属性
和方法
并没有使用装饰器
, 也可以正常运行. 但是会存在引用方法时, this
指向错误的问题.
<button onClick={timer.increaseTimer}>increaseTimer</button>
// 报错: 'this.secondsPassed' is not defind
所以延续旧的装饰器写法
class Timer {
@observable
secondsPassed = 0;
@action
increaseTimer = () => {
this.secondsPassed += 1;
};
}
const timer = makeAutoObservable(new Timer());
定义 stroe 总模块
mobx-react@7.x
中, 推荐使用React Context
来存储状态. Using external state in observer components
先来看总览的代码
// /src/store/index.tsx
import { FC, createContext, useContext } from "react";
import timer from "./timer";
const createStore = () => ({ timer });
const storeValue = createStore();
type TStore = ReturnType<typeof createStore>;
const StoreContext = createContext<TStore | null>(null);
export const StoreProvider: FC = ({ children }) => (
<StoreContext.Provider value={storeValue}>{children}</StoreContext.Provider>
);
export const useStores = () => {
const store = useContext(StoreContext);
if (!store) {
throw new Error("no store");
}
return store!;
};
先讲讲createContext
和useContext
. use context中提到, 创建出来的context
类似一个容器, 用来缓存数据,Provider
为提供数据的容器组件,其中的value
属性则用来配置数据. 而useContext
则会往上找到指定的context
中保存的数据.
创建context
Version 1
const store = { timer }; // 其中'timer'是上文定义的子模块
const StoreContext = createContext(null);
<StoreContext.Provider value={store} />;
这样写是没有问题的. 但是会出现一点小问题. 当逻辑组件引用store
的时候, 1.会提示store
可能是null
(即初始值), 2.不能明确store
中包含的内容.
function App() {
const store = useContext(StoreContext);
// 'store' 可能为空, 由于没有定义类型接口, 'timer' 是不明确的
const secondsPassed = store?.timer?.secondsPassed;
return "";
}
Version 2 先给 stroe 定义子模块的类型
const createStore = () => ({ timer });
const storeValue = createStore();
type TStore = ReturnType<typeof createStore>;
const StoreContext = createContext<TStore | null>(null);
其中ReturnType<typeof createStore>
是根据这篇文章
来使用的, 具体的原理还不是很明白, 先这样写.
createContext
接收泛型参数TStore
后就能在引用时获得提示. 然后在导出useStores
时, 使用!
明确store
一定存在.
export const useStores = () => {
const store = useContext(StoreContext);
if (!store) {
throw new Error("no store");
}
return store!;
};
创建关联 context
的 Provider
export const StoreProvider: FC = ({ children }) => (
<StoreContext.Provider value={storeValue}>{children}</StoreContext.Provider>
);
该组件注入storeValue
, 然后组件内的所有子组件children
都可以获取到context
的数据.
提供获取 store
的自定义 hooks
export const useStores = () => {
const store = useContext(StoreContext);
if (!store) {
throw new Error("no store");
}
return store!;
};
其中store
就是上文创建的storeValue
在根组件中使用 Provider
一般在/src/index.tsx
中
import { StoreProvider } from "@/store";
ReactDOM.render(
<StoreProvider>
<App />
</StoreProvider>,
document.getElementById("root")
);
在子孙组件中引用
// /src/pages/MyComponent.tsx
import { observer } from "mobx-react";
import { useStores } from "@/store";
function MyComponent() {
const { timer } = useStores();
return (
<>
<p>Seconds passed: {timer.secondsPassed}</p>
<button onClick={timer.increaseTimer}>increaseTimer</button>
</>
);
}
export default observer(MyComponent);
最后不要忘了用observer
来将组件转为观察者
.
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!