umi 3.0+ 之后,有了一个@umijs/plugin-model 插件,可以替代繁琐的 dva 调用方式,利用hook的形式导出一个全局的状态组件.
官方给出的例子是这样的:
//src/models/useAuthModel.js
import { useState, useCallback } from 'react'
export default function useAuthModel() {
const [user, setUser] = useState(null)
const signin = useCallback((account, password) => {
// 可以做一些请求相关的事情
}, [])
return {
user,
signin,
signout
}
}
//login.js
import { useModel } from 'umi';
export default () => {
const { user, fetchUser } = useModel('user', model => ({ user: model.user, fetchUser: model.fetchUser }));
return <>hello</>
};
可以看出来,无论在任何一个组件里,只要使用 useModel 引用一下,就可以实现对定义的hook内状态进行调用.
利用这个原理,可以在 src/models 目录下定义一个提供导入的 mobx 状态组件,然后无需引用 Provider 即可实现共享内部的状态.
首先在src/models 目录下定义一个 store
// src/models/useLogin.js
import { flow } from 'mobx'
import { useLocalObservable } from 'mobx-react'
export default function useLogin() {
const store = useLocalObservable(() => ({
loading: false,
setLoading: params => {
store.loading = params
},
verifyLogin: flow(function* (params, callback) {
store.setLoading(true)
try {
const res = yield userAPI.logIn(params)
if (res) {
showSuccess('登录成功')
callback
}
} catch (e) {
showError('账号密码匹配失败')
store.setLoading(false)
}
}),
}))
return {
store
}
}
在这个组件里,利用 mobx-react 的 useLocalObservable 创建一个 observable 对象,并导出供其他组件引用.
里面可以定义所有class类型写法的API,比如 computed 或者 Action .如果是异步调用的函数,可以用 flow 包裹起来,写法上就像 dva 里的 effects .
然后就是像正常的使用一个hook函数一样调用就好了.比起class形式的装饰器调用方式,这种写法更加优雅,逻辑上也更清晰一些:
import React from 'react'
import { observer } from 'mobx-react'
const Login = props => {
const {store: { loading }} = useModel('useLogin', model => ({ store: model.store }))
return (
<div className="login">...</div>
)
}
export default observer(Login)
不知道这种写法有什么问题,我用起来反正比写 useState 好用多了.
继续观察吧.