# react-admin-ant **Repository Path**: Eplayer/react-admin-ant ## Basic Information - **Project Name**: react-admin-ant - **Description**: No description available - **Primary Language**: JavaScript - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2020-06-04 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # react 与 Ant Design Pro ## react 与 vue react 16.8 之前,各有千秋,一个更灵活,一个更智能 | 类别 | react | vue | | -------- | --------------------- | ------------------------- | | 高级方式 | HOC | mixins | | 通讯方式 | Context | Provid/Inject | | 渲染过程 | shouldComponentUpdate | 更快计算 Virtual DOM | | 监听数据 | 强调数据的不可变 | getter/setter(可变数据) | > 渲染过程中,react 可以通过 shouldComponentUpdate 或是 PureComponent 手动细颗粒度的控制更新策略,vue 在 95 %以上的场景下 你都不需要关注 watcher 的问题 --- ### hooks react 16.8 发布 hooks。 [什么是 hooks](http://react.html.cn/docs/hooks-intro.html#motivation),为什么会有 hooks 这个东西 #### 动机 **在组件之间重用有状态逻辑很困难**,React 并没有为组件提供一种可重复使用行为的方法(例如,将其关联到 store 里)。 **复杂的组件变得难以理解**,因为有状态逻辑到处都是。引入太多的抽象,需要在不同的文件之间跳转,并且使得重用组件更加困难。 **容易混淆的 类(class)** 在 webpack 打包压缩时,类不能很好地压缩,并且它们使得热更新加载变得片状和不可靠。 **hooks 允许您在不更改组件层次结构的情况下重用有状态逻辑、允许根据相关内容(例如设置订阅或获取数据)将一个组件拆分为较小的函数、允许在没有类的情况下使用更多 React 的功能** ### class、mixin 、HOC、hooks | 组件服用方式 | 优势 | 劣势 | 状态 | | --- | --- | --- | --- | | 类组件(class) | 发展时间长,接收度广泛 | 只能继承父类 | 传统模式,长期存在 | | Mixin | 可以复制任意对象的任意多个方法 | 组件相互依赖、耦合,可能产生冲突,不利于维护 | 被抛弃 | | 高阶组件(HOC) | 利用装饰器模式,在不改变组件的基础上,动态的为其添加新的能力 | 嵌套过多调试困难,需要遵循某些约定(不改变原始组件,透传 props 等) | 能力强大,应用广泛 | | hooks | 代替 class,多个 HOOKS 互不影响,避免嵌套低于,开发效率高 | 切换到新的思维需要成本 | REACT 未来 | - 不要在循环,条件语句和嵌套函数中调用 hooks - 只在 react 函数组件中调用 hooks #### [hooks Api](http://react.html.cn/docs/hooks-reference.html) - Basic Hooks - - useState - - useEffect - - useContext - Additional Hooks - - useReducer - - useCallback - - useMemo - - useRef - - useImperativeMethods - - useLayoutEffect ### VUE 3.0 中的 hooks Composition API 包含了六个主要 API,与 React Hooks 类似的东西,实现方式不同. _setup_ 函数是一个新的组件选项。作为在组件内使用 Composition API 的入口点。生命周期 - ~~beforeCreate~~ -> 使用 setup() - ~~created~~ -> 使用 setup() 类似于 useEffect,可以把 useEffect hook 看做 componentDidMount、componentDidUpdate、componentWillUnmount 的组合体 - 响应式系统 API - - reactive - - ref - - compouted - - readonly - - watchEffect - - watch react hook 的上手成本相对于 vue 会难一些,vue 天生规避了一些 react 中比较难处理的地方; **vue3.0 会是更智能,更好用的前端框架** --- ### typescript(可选) TypeScript 是 JavaScript 的超集,.js 文件可以直接重命名为 .ts 即可。主要提供可选的静态类型,类和接口。其中一个重要好处是使 IDE 能够在您键入代码时提供更丰富的环境来发现常见错误,增加了代码的可读性和可维护性。 **优势** 1.静态类型化,允许开发人员编写更健壮的代码并对其进行维护。 2. 大型的开发项目,使用 TypeScript 工具来进行重构更容易、便捷 3. 类型推断,类型只是从其使用中推断出来,防止做一些否则会导致运行时错误的事情 4. 类型安全,在编码期间检测错误的功能,而不是在编译项目时检测错误 5. 干净的 ECMAScript6 代码,自动完成和动态输入等因素有助于提高开发人员的工作效率。 **缺点** 1. 有一定的学习成本,需要理解接口(Interfaces)、泛型(Generics)、类(Classes)、枚举类型(Enums)等前端工程师可能不是很熟悉的概念 2. 短期可能会增加一些开发成本,毕竟要多写一些类型的定义,不过对于一个需要长期维护的项目,TypeScript 能够减少其维护成本 3. 集成到构建流程需要一些工作量 4. 可能和一些库结合的不是很完美 # Ant Design Pro ([目录结构](https://pro.ant.design/docs/getting-started-cn)) ## 登录 src/moudel/login effects login 下,获取得到的 response,保存 token 和 userDetail(用户数据)至 localStorage ## layout 页面顺序 1.SecurityLayout dispatch type: 'user/fetchCurrentUser',获取用户信息,以 currentUser 数据流出, 2.BasicLayout dispatch type: 'user/fetchCurrent', 从服务器获取数据, src/utils/request.ts headers 加入 Authorization ,判断 token,然后得到数据返回后,setMenuData(data || []); 更新路由菜单 ## 路由和菜单 - 路由管理 通过约定的语法根据在 config.ts 中配置路由。 - 菜单生成 根据路由配置来生成菜单。菜单项名称,嵌套路径与路由高度耦合。 - 面包屑 组件 PageHeaderWrapper 中内置的面包屑,也可通过 RouteContext 提供的信息自定义生成。 [基本结构 https://pro.ant.design/docs/router-and-nav-cn](https://pro.ant.design/docs/router-and-nav-cn) - name 和 icon 分别代表生成菜单项的文本和图标。 - hideChildrenInMenu 用于隐藏不需要在菜单中展示的子路由。用法可以查看 分步表单 的配置。 - hideInMenu 可以在菜单中不展示这个路由,包括子路由。 - authority 用来配置这个路由的权限,如果配置了将会验证当前用户的权限,并决定是否展示。 ## 从服务器请求菜单 你可以在 src/layouts/BasicLayout.tsx 中修改 menuDataRender,并在代码中发起 http 请求,只需服务器返回下面格式的 json 即可。 ``` const [menuData, setMenuData] = useState([]); useEffect(() => { // 这里是一个演示用法 // 真实项目中建议使用 dva dispatch 或者 umi-request fetch('/api/example.json') .then(response => response.json()) .then(data => { setMenuData(data || []); }); }, []); ... return ( menuData} // ... /> ); ``` ## 权限管理 ### 控制菜单和路由显示 如需对某些页面进行权限控制,只须在路由配置文件 config.ts 中设置 Routes 属性即可,代表该路由的准入权限,pro 的路由系统中会默认包裹 Authorized 进行判断处理。 ``` { path: '/', component: '../layouts/BasicLayout', Routes: ['src/pages/Authorized'], authority: ['admin', 'user'], routes: [ // forms { path: '/form', icon: 'form', name: 'form', routes: [ { path: '/form/basic-form', name: 'basicform', authority: ['admin'],//配置准入权限,可以配置多个角色 component: './Forms/BasicForm', }, ], }, ], } ``` ### 修改当前权限 使用 localStorage 模拟权限角色,实际项目中可能需要从后台读取。 实现了一个简单的刷新权限方法,在登录/注销等关键节点对当前权限进行了更新。 具体可以查看 Authorized.ts 中 reloadAuthorized 的定义。 ## 前端请求流程 前端 UI 交互到服务端处理流程是这样的: UI 组件交互操作; - 调用 model 的 effect; - 调用统一管理的 service 请求函数; - 使用封装的 request.ts 发送请求; - 获取服务端返回; - 1.使用状态管理: - 然后调用 reducer 改变 state; - 更新 model。 - 2.不使用状态管理: - then 方法接收 callback,更新数据 ### 规范 - 数据状态管理 src/models (effects,state,reducers) - api 接口 src/services ## 国际化配置 ### 格式化字符串 如果我们在 en-US.ts 和 zh-CN.ts 中分别作了如下配置 ``` // en-US.ts export default { 'navbar.lang': '中文', }; // zh-CN.ts export default { 'navbar.lang': 'English', }; 我们就可以在组件中这样使用 import { FormattedMessage } from 'umi'; export default () => { return (
); }; ``` 在 object 内 可以这样使用 ``` import { FormattedMessage } from 'umi'; { title: , dataIndex: 'name', } ``` 在相对于的 zh-CN.ts 和 en-Us.ts 添加对应的中英文,像这样 ``` // zh-CN.ts export default { ...pwa, ...component, 'list.name':'规则名称' }; // en-US.ts export default { ...pwa, ...component, 'list.name':'na'me' }; ``` # 坑点 1. umi-request 与 axios 有些许区别,返回数据为简易数据,在 responseType:‘blob’时,返回出错,需配置 getResponse (是否获取源 response, 返回结果将包裹一层)为 true [umi-request README_zh-CN](https://github.com/umijs/umi-request/blob/master/README_zh-CN.md) 2. setState 虽然改成了对象,但是它并不会像 class components 那样帮你自动合并前面的 state,需要手动合并 ``` function DemoComponent(props) { const [state, setState] = useState({ name: 'name', age: 10, count: 0 }) useEffect(() => { fetchData().then((data) => { // some operate for data setState({ name: data.name, age: data.age }) }) }, []) } // 需要手动合并state function DemoComponent(props) { const [state, setState] = useState({ name: 'name', age: 10, count: 0 }) useEffect(() => { fetchData().then((data) => { // some operate for data setState({ ...state, name: data.name, age: data.age }) }) }, []) } ```