中后台场景下,绝大多数页面的数据流转都是在当前页完成,在页面挂载的时候请求后端接口获取并消费,这种场景下并不需要复杂的数据流方案。但是也存在需要全局共享的数据,如用户的角色权限信息或者其他一些页面间共享的数据。那么怎么才能缓存并支持在多个页面直接去共享这部分数据呢。
为了实现在多个页面中的数据共享,以及一些业务可能需要的简易的数据流管理的场景,我们基于 hooks & umi 插件实现了一种轻量级的全局数据共享的方案。实现上我们通过 @umijs/plugin-model 插件来实现一个轻量级的方案来支持这样的需求,该插件已内置在 bigfish@3 中。
在 src/models
目录下新建文件,文件名会成为 model 的 namespace. 允许使用 ts, js, tsx(推荐), jsx(不推荐) 四种后缀。
eg.
demo.ts
的 namespace 是demo
一个 model 的内容需要是一个标准的 JavaScript function,并被默认导出,可以在 function 中使用 hooks.
例如下面的例子就是一个合法的 model:
// demo.tsexport default () => 'Hello World';
在实际使用场景中,model 可以包含其他 hooks,例如下面的计数器的例子:
// counter.tsimport { useState, useCallback } from 'react';export default () => {const [counter, setCounter] = useState(0);const increment = useCallback(() => setCounter((c) => c + 1), []);const decrement = useCallback(() => setCounter((c) => c - 1), []);return { counter, increment, decrement };};
在代码中使用 model,需要从 umi 中导出 useModel。useModel 是一个 React Custom Hook,传入 namespace 即可获取对应 model 的返回值。
import { useModel } from 'umi';export default () => {const message = useModel('demo');return <div>{message}</div>;};
上述例子中的 message 会包含 demo model 的返回值,即:Hello World;
useModel 可以接受一个可选的第二个参数,可以用于性能优化。当组件只需要消费 model 中的部分参数,而对其他参数的变化并不关心时,可以传入一个函数用于过滤。函数的返回值将取代 model 的返回值,成为 useModel 的最终返回值。例如:
import { useModel } from 'umi';export default () => {const { add, minus } = useModel('counter', (ret) => ({add: ret.increment,minus: ret.decrement,}));return (<div><button onClick={add}>add by 1</button><button onClick={minus}>minus by 1</button></div>);};
上面的组件对 counter 的值并不关心,只需要使用 increment 和 decrement 两个方法,因此使用第二个参数,过滤掉了 counter 这一频繁变化的值。
umi 启动时,plugin-model 会监听文件变化,动态生成可消费的 hooks 及对应 ts 类型,因此天然具有较好的代码补全能力。如果需要实现代码跳转,可以配合 vscode 插件,启用后 command + 鼠标左键点击(转到定义) useModel('namespace')
中 namespace 的字符串,即可跳转到对应的 model 文件。
下载链接:https://marketplace.visualstudio.com/items?itemName=litiany4.umijs-plugin-model