020 Umi@4 中如何实现动态菜单

简介: 020 Umi@4 中如何实现动态菜单

image.png

在数据流章节中我有一段这样的描述:

为什么都不是最佳实践了,我还要一直提 dva


因为纯 hooks 的数据流方案,存在天然的局限性,因为 react hook 只能用在 react 的上下文环境中,但是在 Umi 中我们还有一些环节是不在 react 的上下文的,比如如果我们要前置判断用户登录情况,或者提前获取用户可访问菜单数据,或者其他的一些项目前置数据,我们都需要“上升”我们的数据流方案。


其实这一段我是想描述在 Umi 项目中还存在不在 React 生命周期中的数据流管理时机,所以我们依旧需要 dva 来管理我们的项目数据,其实最主要的点还是 dva 是一个很流行的数据流管理方案,在我们的项目中有很长的使用情况,团队内对它都比较熟悉,因此就算出现了其他可替代的方案,我们依旧会选择使用较为“古老”的方案。


西门吹风凉飕飕 提到的疑惑,其实在第 10 课使用 Umi 配置,定制化你自己的 Umi 框架中,我们讲解 Umi 中的运行时配置 - render 时,就已经演示过代码了。那时候,我们还没讲解到数据流和请求这些,今天我们就将这几个方案串联起来。



升级插件

@alita/plugins 升级到 3.0.3,因为我们添加了一个获取 Dva app 的 Api ,这使你能够在任何的 js 环境中继续使用 Dva

"@alita/plugins": "3.0.3",
复制代码

`@alita/plugins` 和 `@umijs/plugins` 中的 dva 插件有什么差别吗?

其实这两个插件现在的功能是一致的,alita 中的 Dva 插件就是从 umijs 中复制出来的,唯一的不同是,alita 中的插件,添加了约定的 Dva module 类型定义。可以更加规范的在 Typescript 中使用 Dva。



Mock 数据

在第 16 课 Umi 项目中的菜单与权限 中,我们讲解了 Umi 项目中的菜单与权限,我们使用了unaccessible 数组来管理我们的菜单,所以我们想将它转移到本地的“服务端”。

新建 Mock 文件 mock/accessible.ts

export default {
  "POST /api/rule": {
    success: true,
    data: ["/hooks", "/useEffect", "/usemodel", "/useState"],
  },
};
复制代码

如果你不知道这有什么用,请阅读第 18 课 Umi 中使用 mockjs 完善前后端分离



增加配置

import { defineConfig } from "umi";
export default defineConfig({
  plugins: [
    // 其他插件不用删除,这里只是简略展示
    require.resolve("@alita/plugins/dist/dva"),
  ],
  // 其他配置不用删除,这里只是简略展示
  dva: {
    enableModelsReExport: {},
  },
});
复制代码


enableModelsReExport 配置就是 alita 中的 Dva 插件特有的,会将 module 文件中的 State 类型导出,这有个要求,每个 module 必须写明 State 的类型,不然程序就会报错。通过约定,我们可以很方便的解决问题。

当然了如果你觉得这个功能你不需要,你可以不开启这个配置,或者直接使用 umijs/plugins 中的 Dva 插件。


api.config.dva?.enableModelsReExport
    ? models
        .map((model: { file: string; namespace: string }) => {
          const { file, namespace } = model;
          // prettier-ignore
          // export type { IndexModelState } from '/Users/xiaohuoni/next-alita-app/src/models/index';
          return `export type { ${namespace.replace(/( |^)[a-z]/g, (L) => L.toUpperCase())}ModelState } from '${winPath(file.replace(extname(file), ''))}';`;
        })
        .join('\r\n')
    : ''
复制代码



添加 Dva module 文件

新建 Dva module 文件 src/models/global.ts

import { Reducer } from "umi";
export interface GlobalModelState {
  unaccessible: string[];
}
export interface GlobalModelType {
  namespace: "global";
  state: GlobalModelState;
  reducers: {
    save: Reducer<GlobalModelState>;
  };
}
const GlobalModel: GlobalModelType = {
  namespace: "global",
  state: {
    unaccessible: [],
  },
  reducers: {
    save(state, action) {
      return {
        ...state,
        ...action.payload,
      };
    },
  },
};
export default GlobalModel;
复制代码

注意以上内容必须的是 GlobalModel 对象,剩余部分都是为了更好的用类型去定义和规范 GlobalModel 对象。



在 render 中发起请求

在运行时配置中 src/app.tsrender 中发起请求,如果你不知道 render 是啥,请翻阅第 10 课使用 Umi 配置,定制化你自己的 Umi 框架

import { request, getDvaApp } from "umi";
export function render(oldRender: any) {
  request("/api/accessible").then(({ data }) => {
    const app = getDvaApp();
    app?._store.dispatch({
      type: "global/save",
      payload: { unaccessible: data },
    });
  });
  oldRender();
}
复制代码

这里我们通过 getDvaApp 获取到当前项目中的 Dva app,然后使用 _store 上的 dispatch 发起一个 action 将数据更新到 global modules 中。



将 module 数据绑定到页面上

将 global 的数据,绑定到全局布局上, src/layouts/index.tsx

import { connect } from "umi";
import type { ConnectProps, GlobalModelState } from "umi";
interface AppProps extends ConnectProps {
  global: GlobalModelState;
}
const App: React.FC<AppProps> = ({ global }) => {
    const { unaccessible } = global;
    return (<></>)
}
export default connect(({ global }: { global: GlobalModelState }) => ({
  global,
}))(App);
复制代码

以上操作就将页面和 module 进行了双向绑定,只要 global 数据发生变化,就会促使页面进行重绘。

我们只需要取出 global 中的 unaccessible 代替原来“写死”的 unaccessible 即可。



总结

以上操作,看起来比较繁琐,但是如果你对各个概念都有了一定了解,那阅读起来就会很轻松,觉得逻辑非常的清晰。如果你有任何疑问,可以去看看前面的课程,也可以在评论区和我互动。

你应该可以从我的行文内容看出来,我是没有任何“存稿”的,跟这个系列文章,有点类似半直播的方式。我觉得这比我自己“埋头苦干”,要有趣的多,也希望你会喜欢。



目录
相关文章
如何在 Umi 中使用 Keep Alive
如何在 Umi 中使用 Keep Alive
4375 0
如何在 Umi 中使用 Keep Alive
|
移动开发 缓存 自然语言处理
ant-design-pro项目开发全攻略(用这个做博客网站模板不要太快,一招鲜吃遍天)
ant-design-pro项目开发全攻略(用这个做博客网站模板不要太快,一招鲜吃遍天)
ant-design-pro项目开发全攻略(用这个做博客网站模板不要太快,一招鲜吃遍天)
|
存储 JavaScript 网络安全
nodejs:本地安装nvm实现nodejs多版本管理及切换版本
nodejs:本地安装nvm实现nodejs多版本管理及切换版本
2988 0
|
6月前
|
算法 搜索推荐
快速排序-数据结构与算法
快速排序(Quick Sort)是一种基于分治法的高效排序算法。其核心思想是通过选择基准(pivot),将数组划分为左右两部分,使得左侧元素均小于基准,右侧元素均大于基准,然后递归地对左右两部分进行排序。时间复杂度平均为 O(n log n),最坏情况下为 O(n²)(如数组已有序)。空间复杂度为 O(1),属于原地排序,但稳定性不佳。 实现步骤包括编写 `partition` 核心逻辑、递归调用的 `quickSort` 和辅助函数 `swap`。优化方法有随机化基准和三数取中法,以减少最坏情况的发生。
399 13
|
11月前
|
前端开发
如何定义和使用React泛型组件
通过合理地定义和使用React泛型组件,可以提高代码的复用性和可维护性,同时增强类型安全性,使React应用程序的开发更加高效和可靠。
351 65
|
缓存 JavaScript 安全
【Ant Design Pro】使用ant design pro做为你的开发模板(四) 联调正式后台接口与运行时全局配置
【Ant Design Pro】使用ant design pro做为你的开发模板(四) 联调正式后台接口与运行时全局配置
1897 0
【Ant Design Pro】使用ant design pro做为你的开发模板(四) 联调正式后台接口与运行时全局配置
|
存储 索引
antd中table组件选中单行换样式(比如背景颜色)
在Ant Design (antd)的Table组件中,可以通过设置`onRow`属性来定义行点击事件,从而改变被点击行的样式,如背景颜色。`onRow`是一个函数,返回一个对象,对象包含事件处理函数,如`onClick`。同时,使用`rowClassName`属性来指定行的类名,结合状态管理,可以实现点击某行后改变其背景颜色的效果。具体实现时,需要在组件状态中保存当前被点击行的索引,然后通过`rowClassName`判断并返回相应的类名。
1205 2
antd中table组件选中单行换样式(比如背景颜色)
Threejs绘制传送带
这篇文章详细介绍了如何使用Three.js绘制一个动态的传送带模型,包括传送带的几何体创建、纹理应用以及实现带体循环移动的动画效果。
252 0
Threejs绘制传送带
Each child in a list should have a unique “key“ prop. Check the render method的报错解决
Each child in a list should have a unique “key“ prop. Check the render method的报错解决
|
前端开发 搜索推荐 SEO
【专栏:HTML 与 CSS 实践篇】使用 HTML 与 CSS 构建个人博客网站
【4月更文挑战第30天】本文介绍了使用HTML和CSS构建个性化个人博客网站的步骤。首先,规划设计网站主题、风格和结构;接着,利用HTML搭建首页、文章列表页和文章详情页的结构;然后,通过CSS设计整体风格、布局和交互效果;填充内容并进行SEO优化;最后,通过实际案例展示HTML和CSS的应用。构建博客网站不仅是展示自我和分享知识的平台,也是提升技能和创意实践的好机会。
373 1