项目开发常见问题
以下内容对React_Ts项目中常见问题进行说明,如需进行代码对照,可参考目录下 react19_ts 项目内实际代码,文档与代码会在git上持续补充
git仓库地址:https://gitee.com/xiaoli-account/react19_ts
如何创建一个 react 项目?
- 请参考 vite 创建项目命令搭建第一个 vite 项目
npm create vite@latest react19_ts -- --template react-ts
- 也可参考官方文档项目的由 0 到 1 的创建方式从零构建一个 React 应用
// 下载项目git clone https://gitee.com/xiaoli-account/react19_ts.git# 使用 npm 为前端项目安装依赖npm install# 为 mock 项目安装依赖cd mock npm install# 启动前端项目 并 启动 mock 服务npm run mock# 访问地址:http://localhost:4200
项目背景项目是怎么从零开始的?
- 可参考项目根目录 docs 下得文档,或项目内各个目录下得 readme.md 文档
- 可以让你了解 React_Ts 项目是如何从零发展到现在的
项目内包含了 mock 服务还有 koa 的服务,全部都可以测试使用吗?
- Mock 服务目前已经完成到足以支撑 React_Ts 项目的基本运行
- Koa 服务目前处于开发阶段,还无法支撑 React_Ts 项目的基本运行
当前项目可以作为前端脚手架进行项目开发吗?
- 是的可以的,完全不用担心无法支撑真实项目的体量,基础开发已经结束,足以支撑项目的正常开发,细节优化尚未结束,由于不同项目要求不同所以细节优化仅会在必要性问题点进行优化
- 建议使用当前脚手架的开发人员配置:2-3 人,如 1 人开发的话,在 mock 服务、service 部分、api-connection 基础功能中间件、i18n 国际化、亮色/暗色主题色兼容等部分会有些捉襟见肘
src\layout 目录下内容是否有些过重?
- 不是的,有关 layout 内容过重是有原因的,我的本意是想要一个可复用的 layout,达到复制 layout 就可以形成一个新脚手架、完善的脚手架目的
- 所以在 layout 目录下同时包含了很多项目重常用内容
src\webview 目录是什么作用?
- src\webview 目录是为了快速集成外部 html 页面到 React_Ts 的组件中,达到 uni-app/微信小程序中的 webview 作用
src_ai 目录是做什么用的?
src_ai 目录主要作用是防止脚手架搭建的项目被 AI 代码污染,形成屎山代码无法维护src_ai目录主要依赖于 src_ai\ai-knowledge\readme.md 的知识库目录,使用 AI 时,须将项目 AI 使用规则 src_ai\ai-knowledge\lee-custom-llms-text\llms.txt 文档喂给 AI
项目使用双目录开发,你如何处理菜单管理的路由 components 配置?
- 针对双目录产生的路径紊乱,我通过两个双目录配置解决,参考下方文件或代码块
- 1、src\pages\sso-loading\index.tsx L99-163 transformRoutes 函数
- 2、vite.config.ts L201-207 alias 配置
- 3、tsconfig.app.json L22-26 ts 文件识别 path 配置
// src\pages\sso-loading\index.tsx L99-163function transformRoutes(routes: any[]): any[] {if (!routes || !Array.isArray(routes)) return [];// 使用 import.meta.glob 收集所有的页面组件模块,防止 Vite 动态 import 解析警告const pageModules = import.meta.glob("@/pages/**/*.tsx");const aiPageModules = import.meta.glob("@ai/pages/**/*.tsx");return routes.map((route: any) => { // 获取原始的 java 数据字段 const reactRoute = { ...route }; // 映射至 react 格式所需的字段 reactRoute.path = route.route_path; reactRoute.name = route.name; // 如果存在 redirect 属性并且不为空 if (route.redirect) { reactRoute.redirect = route.redirect; } // 组装 meta 数据 reactRoute.meta = {title: route.title, ...route.meta, // 兼容如果后续接口直接返回了metaicon: route.icon || "AppstoreOutlined",pagePermission: route.permission,hidden: !!route.hidden,keepAlive: !!route.keep_alive, }; // 处理由后端传递的 component_path 并转换为真正的 react 组件 if (route.component_path) {// 解决 Vite 动态 import 全局无扩展名的警告const targetPath1 = `/src/pages/${route.component_path}.tsx`;const targetPath2 = `/src/pages/${route.component_path}/index.tsx`;const targetAIPath1 = `/src_ai/pages/${route.component_path}.tsx`;const targetAIPath2 = `/src_ai/pages/${route.component_path}/index.tsx`;if (pageModules[targetPath1]) { reactRoute.component = pageModules[targetPath1]; } else if (pageModules[targetPath2]) { reactRoute.component = pageModules[targetPath2]; } else if (aiPageModules[targetAIPath1]) { reactRoute.component = aiPageModules[targetAIPath1]; } else if (aiPageModules[targetAIPath2]) { reactRoute.component = aiPageModules[targetAIPath2]; } else { console.warn(`小李警告:[sso-loading/index.tsx] 无法匹配到路由组件: ${route.component_path}` ); } } // 递归处理子层级,直至没有 children if ( route.children &&Array.isArray(route.children) && route.children.length > 0 ) { reactRoute.children = transformRoutes(route.children); } return reactRoute; }); }
// vite.config.tsresolve: { alias: {'@': path.resolve(__dirname, './src'),'@AI': path.resolve(__dirname, './src_ai'),'@ai': path.resolve(__dirname, './src_ai'), },},
// tsconfig.app.json"paths": { "@/*": ["src/*"], "@AI/*": ["src_ai/*"], "@ai/*": ["src_ai/*"]},
内部 input 聚焦,控制父级结构样式?
.parent{ &:focus-within { }}
ant design 表格组件涉及固定列时,导致隐藏列显示?
scroll={{ x: "max-content" }} 需要在 table 组件增加当前属性
<Tablecolumns={columns}dataSource={data}rowKey="id"loading={loading}pagination={false}scroll={{ x: "max-content" }}expandable={{ expandedRowKeys, onExpandedRowsChange: (keys) => setExpandedRowKeys(keys as Key[]), }} />
表单的多列处理,建议使用单个 row,多个 col 形式,便于不同 if 情况下,整体布局完整?
<Form><Rowgutter={16}><Colspan={24}></Col><Colspan={12}></Col><Colspan={8}></Col></Row></Form>
表单内如何根据不同情况进行 if 的条件取值判断?
// 使用Form.Item进行外层嵌套<Form.Item noStyle shouldUpdate={(prev: any, curr: any) => prev.menu_type !== curr.menu_type } >// 取值判断,控制条件显示 {({ getFieldValue }) => {const menu_type = getFieldValue("menu_type");return menu_type !== "Directory" ? ( <Colspan={24}> </Col> ) : null; }}</Form.Item>
Mock 服务是如何实现页面上的 crud 保证刷新也不丢数据的?
- 1、首先 Mock 服务数据是存在 Node 进程的内存中
- 2、crud 本质是操作 Node 进程内存里的变量值
- 3、所以 Node 进程不停止,Mock 服务数据就不会丢失,就可以达到模拟真实数据接口的情形
路由配置为什么不用缓存处理?
- 路由数据禁止持久化,会导致 react 路由配置对象组件渲染失败,所以对路由进行了单独处理,页面刷新或路由初始化时获取缓存内的 userInfo.routes 结构重新初始化路由配置
权限系统、路由系统全部初始化了,仍然无法正常登录访问首页?
- 检查 src/pages/sso-loading/index.tsx 的 initSubsystemConfig 函数,权限系统应在路由系统之前初始化