简介
中后台场景下,绝大多数页面的数据流转都是在当前页完成,在页面挂载的时候请求后端接口获取并消费,这种场景下并不需要复杂的数据流方案。但是也存在需要全局共享的数据,如用户的角色权限信息或者其他一些页面间共享的数据。那么怎么才能缓存并支持在多个页面直接去共享这部分数据呢。
为了实现在多个页面中的数据共享,以及一些业务可能需要的简易的数据流管理的场景,我们基于 hooks & umi 插件实现了一种轻量级的全局数据共享的方案。实现上我们通过 @umijs/plugin-model 插件来实现一个轻量级的方案来支持这样的需求,该插件已内置在 bigfish@3 中。
在学习 Ant Design Pro 之,我首先学习的 redux,之后有学习了mobx,感觉mobx是要比redux简单一点,之后在学习 Ant Design Pro V4 后接触到了 dva,又感觉简化了好多,过了几个月,V5发布了,然后看到了V5的数据流,简直成傻瓜式操作~,不得不说~,我钦佩蚂蚁团队~
当然 dva 在 V5 中 也可以使用,至于怎么使用,可以看看 这位大神的~~~ 聊聊 effects 与 reducers
废话说的有点多~,我们来看看具体怎么使用~
全局状态 initialState
首先,我们先来说说 V5 自带的initialState吧,用官方的话说是:
initialState 在 v5 中替代了原来的自带 model,global,login,setting 都并入了 initialState 中。我们需要删除 src/models/global.ts,src/models/login.ts,src/models/setting.ts ,并且将请求用户信息和登陆拦截放到 src/app.tsx 中。
理解下官方的话:
- 首先,他是一个由官方内置的model,可以当做最外层的model
- 其次,我们可以将全局的状态放进去,以供单独的文件去调用,如:用户信息,权限等级等~
- 在这里,我把一开始调用的位置放在了
**/scr/utils/initData**
文件下,方便调用
我们先来看看如何使用吧
import { useModel } from 'umi';
export default () => {
const { initialState, loading, error, refresh, setInitialState } = useModel('@@initialState');
return <>{initialState}</>
};
使用起来非常的方便,介绍下所有参数的用途
**initialState**
: 返回全局状态,也就是 getInitialState
的返回值**setInitialState**
: (state:any) => 手动设置 initialState 的值,手动设置完毕会将 loading 置为 false.loading
: getInitialState 是否处于 loading 状态,在首次获取到初始状态前,页面其他部分的渲染都会被阻止。loading 可用于判断 refresh 是否在进行中。error
: 当运行时配置中,getInitialState throw Error 时,会将错误储存在 error 中。refresh
: () => void 重新执行 getInitialState 方法,并获取新数据。
单独设置
我们先说说存放的文件位置:src/model
为了更好的说明,我们来举个小例子~
文件位置 src/models/test/modelTest.ts
import { useState, useCallback } from 'react';
interface Props {
count?: number
}
const initInfoValue: Props = {
count: 1,
}
export default function modelTest() {
const [init, setInitValue] = useState(initInfoValue);
const [loading, setLoading] = useState(false);
const waitTime = (time: number = 2000) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
const setInit = useCallback(async(res:any) => {
setLoading(true)
await waitTime()
setLoading(false)
setInitValue({count: res})
}, [init])
const setAdd= useCallback((res:any) => {
setInitValue({ count: res +1})
}, [init])
return {
loading,
init,
setAdd,
setInit
};
}
在这边做了 init 值, loading 状态, setaAdd 和 setInit 两个方法,下面我们将看看如何调用
import React from 'react';
import { useModel } from 'umi';
import { Button } from 'antd';
export const MockModel: React.FC<any> = () => {
const { init, setInit, setAdd, loading } = useModel('test.modelTest');
return <div>
<div style={{ marginBottom: 14 }}> count 对应的值{init.count}</div>
<Button loading={loading} style={{ marginBottom: 18 }} type='primary' onClick={() => setInit(5)} >设置count为5</Button>
<br />
<Button type='primary' onClick={() => setAdd(init.count)} >累加1</Button>
</div>
}
只要把对应的方法,值全部返回,然后在调用即可,真是简单的过分了~~~
性能优化
useModel
第二个可选参数可用作性能优化,只消费 model
中的部分参数,而不使用其他参数, 并且返回的值则是 useModel
最终的返回值
我们以上述为例
import React from 'react';
import { useModel } from 'umi';
import { Button } from 'antd';
export const MockModelRet: React.FC<any> = () => {
const { init, setAdds } = useModel('test.modelTest', (ret) => {
return {
init: ret.init,
setAdds: ret.setAdd
}
});
return <div>
<div style={{ marginBottom: 14 }}> count 对应的值{init.count}</div>
<Button type='primary' onClick={() => setAdds(init.count)} >累加1</Button>
</div>
}