创建loading仓库
import { extendObservable, makeAutoObservable } from 'mobx'
class Loading {
constructor() {
makeAutoObservable(this)
}
registerMobxAction(key: string) {
if (key in this) return
extendObservable(this, { [key]: false })
}
setLoading(key: string, value: boolean) {
// @ts-ignore
this[key] = value
}
}
const loadingStore = new Loading()
// @ts-ignore
export const loadingEffectGetter = (key: string): boolean => loadingStore[key]
export function createLoadingEffect<T = any>(store: any, name?: string): T {
const target = Object.create(null)
// @ts-ignore
// 防止类名生产打包时被webpack混淆
const fatherClassName = name || store.constructor.name
// @ts-ignore
const keys = Reflect.ownKeys(store.constructor.prototype)
keys.forEach((key) => {
if (typeof key === 'string' && store[key]?.isMobxAction) {
loadingStore.registerMobxAction(`${fatherClassName}/${store[key].name}`)
}
})
return new Proxy(target, {
get(obj, key) {
if (typeof key === 'string' && store[key]?.isMobxAction) {
// 劫持mobx action 自动注入loading
return (...args: any[]) => {
loadingStore.setLoading(`${fatherClassName}/${key}`, true)
const res = store[key].bind(store)(...args)
if (res instanceof Promise) {
return Promise.resolve(res)
.then((promiseRes) => Promise.resolve(promiseRes))
.catch((e) => Promise.reject(e))
.finally(() => {
loadingStore.setLoading(`${fatherClassName}/${key}`, false)
})
}
loadingStore.setLoading(`${fatherClassName}/${key}`, false)
return res
}
}
return store[key]
},
}) as T
}
export default loadingStore
如何使用
创建test.store.ts文件
import { createLoadingEffect } from '@/store/loading'
class Test {
constructor() {
makeObservable(this)
// 引入方法一
return createLoadingEffect(this, 'Test')
}
@action
async testAction() {
await new Promise((resolve) => setTimeout(resolve, 3000))
}
}
export default new Test()
创建xxx.tsx组件
import { observer } from 'mobx-react-lite'
import testStore from 'test'
import { loadingEffectGetter } from '@/store/loading'
const XXX = () => {
useEffect(() => {
testStore.testAction()
}, [])
// loading 对应的key值: Test/testAction
const loading = loadingEffectGetter('Test/testAction')
return loading ? (<div>loading...</div>) : <div>内容</div>
}
export default observer(XXX)