项目源码:https://gitee.com/kong_yiji_and_lavmi/react-ant-admin
项目介绍网站:https://z3web.cn/doc-react-ant-admin/guide/start.html
建议学完React基本知识后,此项目巩固和了解基本知识在项目中如何使用,以及项目架构。
在此基础上,进行二次开发react-bpmn
React-ant-admin
1.代理转发(解决跨域)
在React项目中设置代理转发,通常用于解决开发环境中的跨域问题。以下是两种常用的设置代理转发的方法:
方法一:在package.json
中配置
这是最简单的方法,但只能配置一个代理。
- 打开React项目的
package.json
文件。 - 在文件中找到或添加
"proxy"
字段,并设置为目标域名地址和端口号。例如:
{// ...其他配置"proxy": "http://localhost:5000"
}
- 保存
package.json
文件并重启React项目。
此时,当React项目中的请求无法找到对应的路由时,会自动转发到proxy
字段指定的目标域名地址上。
方法二:使用http-proxy-middleware
插件⭐⭐⭐
这种方法可以配置多个代理,更加灵活。
- 安装
http-proxy-middleware
插件:
npm install http-proxy-middleware --save
- 在React项目的
src
目录下创建一个名为setupProxy.js
的文件。 - 在
setupProxy.js
文件中进行代理配置。例如:
const { createProxyMiddleware } = require('http-proxy-middleware');module.exports = function(app) {app.use(createProxyMiddleware('/api1', {target: 'http://localhost:3001', // 目标服务器地址changeOrigin: true, // 是否改变源地址pathRewrite: { '^/api1': '' }, // 去除请求前缀}));app.use(createProxyMiddleware('/api2', {target: 'http://localhost:3002', // 另一个目标服务器地址changeOrigin: true,pathRewrite: { '^/api2': '' },}));// 可以继续添加更多的代理配置
};
- 保存
setupProxy.js
文件并重启React项目。
此时,当React项目中的请求以/api1
或/api2
为前缀时,会分别转发到http://localhost:3001
和http://localhost:3002
上。
注意事项
- 在使用
http-proxy-middleware
插件时,确保setupProxy.js
文件位于src
目录下,并且文件名不能更改。 - 在配置代理时,
target
字段指定的是目标服务器的地址,changeOrigin
字段通常设置为true
以改变源地址,pathRewrite
字段用于去除请求前缀。 - 代理配置完成后,需要重启React项目才能使配置生效。
通过以上两种方法,您可以在React项目中设置代理转发,从而解决开发环境中的跨域问题。
项目环境变量管理
env-cmd 详解
一、定义与功能
env-cmd 是一个简洁的 Node.js 程序,它允许你在执行命令时加载指定的环境文件,从而轻松管理环境变量。这个工具特别适用于开发过程中需要处理不同环境下的配置变量的场景。
二、主要特性
- 支持多种环境文件格式:env-cmd 支持
.env
(key=value 格式)、.env.json
和.env.js
(JavaScript 对象或 Promise)等多种环境文件格式。 - 灵活的环境配置:通过
.env-cmdrc
或.env-cmdrc.js
文件,你可以定义多个环境配置,并在运行时通过命令行参数指定要使用的环境。 - 与 npm 脚本集成:env-cmd 可以直接与 npm 脚本集成,只需在
package.json
的scripts
中调用即可。 - 安全性:虽然不建议将敏感数据存储在公共仓库中,但 env-cmd 提供了方便的方式来管理和保护这些信息(例如,通过环境变量文件而非硬编码在代码中)。
- 扩展性:通过
--expand-envs
选项,可以将命令行参数中的环境变量进行展开,提高可编程性。 - 调试友好:
--verbose
选项可用于输出调试信息,帮助排查问题。
三、使用方法
-
安装:通过 npm 或 yarn 安装 env-cmd。
npm install env-cmd --save-dev # 或者 yarn add env-cmd --dev
-
创建环境变量文件:在项目根目录下创建
.env
文件(或其他支持的文件格式),并在其中定义环境变量。 -
配置 npm 脚本:在
package.json
的scripts
部分添加使用 env-cmd 的脚本命令。{"scripts": {"start": "env-cmd -f .env.development node index.js","build": "env-cmd -f .env.production webpack --config webpack.config.js"} }
-
运行命令:通过 npm 脚本或直接运行 env-cmd 命令来加载环境变量并执行相应的操作。
四、高级用法
-
指定环境配置:使用
-e
或--env
选项指定要加载的环境配置名称(如果使用了.env-cmdrc
或.env-cmdrc.js
文件)。env-cmd -e production node index.js
-
环境变量插值:在
.env
文件中,你可以引用其他环境变量来实现环境变量插值。API_URL=http://${API_HOST}:${API_PORT} API_HOST=localhost API_PORT=3000
.env-cmdrc.js 详解
一、定义与用途
.env-cmdrc.js
是 env-cmd 的一个配置文件,用于定义和共享多个环境配置。通过这个文件,你可以更灵活地管理和切换不同的环境变量。
/*** env-cmd 文档地址 https://github.com/toddbluhm/env-cmd#-help* 命令行使用: env-cmd --verbose -e mode_name node file.js * mode_name: 对应 mode 里面的 属性(key) 例如 development development_color* 运行结果:* 取出 对应 mode_name 的 值(value) Object.keys方法 把 key-value 绑定到 process.env 上* 如 : development(mode_name): { test : "123" } => process.env.test = "123"* 最终能够在整个项目中 使用 process.env.test*/
二、文件结构
.env-cmdrc.js
文件应该导出一个包含多个环境配置的对象。每个环境配置都是一个键值对对象,其中键是环境变量的名称,值是环境变量的值。
module.exports = {development: {REACT_APP_API_URL: 'http://localhost:3000/api',// 其他开发环境变量...},production: {REACT_APP_API_URL: 'https://api.example.com/api',// 其他生产环境变量...},// 可以定义更多环境配置...
};
三、使用方法
-
创建
.env-cmdrc.js
文件:在项目根目录下创建.env-cmdrc.js
文件,并按照上述结构定义环境配置。 -
运行命令:在命令行中使用
-e
或--env
选项指定要加载的环境配置名称。env-cmd -e development node index.js
-
与 npm 脚本集成:你也可以在
package.json
的scripts
部分中集成.env-cmdrc.js
文件的使用。{"scripts": {"start:dev": "env-cmd -e development node index.js","start:prod": "env-cmd -e production node index.js"} }
综上所述,env-cmd 和 .env-cmdrc.js
提供了强大的环境变量管理能力,帮助开发者在各种场景下轻松应对环境变量的管理问题。无论是个人开发者还是团队成员,都能从这些工具中受益。
此项目解读
.env-cmdrc.js:配置多种环境(开发与生产)
**config**
const devConfig = {PORT: 3000, // 启动端口HOST: "0.0.0.0", // 监听地址REACT_APP_ROUTERBASE: "/react-ant-admin", // react路由基础路径REACT_APP_API_BASEURL: "http://127.0.0.1:8081/api/react-ant-admin", //请求地址PUBLIC_URL: "/react-ant-admin",// 静态文件路径
}
const proConfig = {REACT_APP_ROUTERBASE: "/react-ant-admin", // react路由基础路径REACT_APP_API_BASEURL: "/api/react-ant-admin", //请求地址PUBLIC_URL: "/react-ant-admin",// 静态文件路径BUILD_PATH: "react-ant-admin", // 打包 文件夹名称
}**mode**
// 本地mock 运行
development_mock: {...devConfig,REACT_APP_MOCK: "1", // 1 为开启mock
},// 主题色 和 本地mock 运行
development_color_mock: {...devConfig,COLOR: "true",REACT_APP_MOCK: "1",
},// 打包 :无主题 无mock
production: proConfig,
package.json中以不同形式启动项目
"scripts": {"start:mock": "node color && env-cmd --verbose -e development_mock node scripts/start.js","start:mock_color": "env-cmd --verbose -e development_color_mock node color && env-cmd --verbose -e development_color_mock node scripts/start.js","build": "node color && env-cmd --verbose -e production node scripts/build.js",
},
详细解释一下此段脚本
"start:mock": "node color && env-cmd --verbose -e development_mock node scripts/start.js",
–verbose:选项可用于输出调试信息,帮助排查问题。
development_mock :.env-cmdrc.js中配置的模式。
按需加载
在React中,loadable
是一个用于代码拆分(Code Splitting)的库,可以帮助你按需加载组件,从而提高应用的性能。代码拆分允许你将应用的代码分成小块,这样用户只有在需要的时候才会下载相应的代码,从而减少了初始加载时间。
尽管 loadable
库本身已经有一段时间没有更新,React 社区现在更推荐使用内置的 React.lazy
和 Suspense
来实现类似的功能。以下是如何使用这两种方式来实现代码拆分的示例:
使用 React.lazy 和 Suspense
-
安装 React 和 React-DOM(如果你还没有安装的话):
bash复制代码npm install react react-dom
-
创建一个需要按需加载的组件(例如
OtherComponent.js
):// OtherComponent.js import React from 'react';const OtherComponent = () => {return <div>This is the Other Component!</div>; };export default OtherComponent;
-
在你的主应用中使用
React.lazy
和Suspense
:// App.js import React, { Suspense, lazy } from 'react';const OtherComponent = lazy(() => import('./OtherComponent'));const App = () => {return (<div><h1>Hello, World!</h1><Suspense fallback={<div>Loading...</div>}><OtherComponent /></Suspense></div>); };export default App;
lazy
函数允许你定义一个动态导入的组件。Suspense
组件包裹动态加载的组件,并显示一个 fallback UI(例如一个加载指示器),直到动态加载的组件完成加载。
使用 Loadable Components 库(已过时,但了解原理)
虽然 loadable
库现在不太推荐使用,但了解它的原理仍然是有价值的。以下是如何使用 loadable-components
的示例(注意:你可能需要先安装这个库):
-
安装 loadable-components:
bash复制代码npm install @loadable/component
-
创建一个需要按需加载的组件(例如
OtherComponent.js
,与上面的相同)。 -
在你的主应用中使用 Loadable:
// App.js import React from 'react'; import loadable from '@loadable/component';const OtherComponent = loadable(() => import('./OtherComponent'), {fallback: <div>Loading...</div>, });const App = () => {return (<div><h1>Hello, World!</h1><OtherComponent /></div>); };export default App;
loadable
函数接受一个加载组件的函数和一个配置对象,配置对象中可以指定一个 fallback UI。
总结
虽然 loadable-components
库提供了一种实现代码拆分的方法,但 React 内置的 React.lazy
和 Suspense
提供了更简单且更直接的方式来处理动态导入和加载状态。因此,如果你正在开发一个新的React应用,建议使用 React.lazy
和 Suspense
。
Redux全局状态管理
https://blog.csdn.net/m0_55049655/article/details/142662383
https://blog.csdn.net/m0_55049655/article/details/143029565
index.js```jsx
import { createStore, combineReducers } from “redux”;
import MenuReducer from “./menu/reducer”;
import UserReducer from “./user/reducer”;
import LayoutReducer from “./layout/reducer”;
import VisibelReducer from “./visibel/reducer”;
const reducer = combineReducers({
menu: MenuReducer,
user: UserReducer,
layout: LayoutReducer,
componentsVisible: VisibelReducer,
});
const store = createStore(
reducer,
process.env.NODE_ENV === “development” &&
window.REDUX_DEVTOOLS_EXTENSION &&
window.REDUX_DEVTOOLS_EXTENSION()
);
export default store;
**App.js中全局状态使用**
import { Provider } from “react-redux”;
import store from “./store”;
function App() {
return (
<Suspense fallback={
{process.env.showColorSet&&}
);
}
下图中dispatch(hooks内的js)对应于上图的action,reducer对应reducer,action.js封装内容是ruducer函数第一个参数,主要是actionType(如:加或减),所有又封装了actionTypes.js。
layout.js
import { useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import { changeLayoutMode } from "../action";
import { getLayoutMode } from "../getters";export const useStateLayout = () => useSelector(getLayoutMode)export function useDispatchLayout() {const dispatch = useDispatch()const stateChangeLayout = useCallback((type, mode) => dispatch(changeLayoutMode(type, mode)), [dispatch])return {stateChangeLayout}
}
reducer(layout/reducer.js)
import * as actionTypes from "./actionTypes";
import { getLayoutMode } from "@/utils";
const localLayout = getLayoutMode()
const layout = (Array.isArray(localLayout) && localLayout) || [actionTypes.TWO_COLUMN];export default function reducer(state = layout, action) {const { type, mode } = action;switch (type) {case "push": {if (!mode) {return state}let lastMode = state[state.length - 1]console.log(mode, lastMode);if (lastMode === mode) {return state}const sliceNum = state.length > 1 ? 1 : 0return state.slice(sliceNum).concat(mode)}case "pop": {if (state.length > 1) {state = state.slice(0, 1)} else {state = layout}return state}default: {return state}}
}
action(layout/action.js)
export const changeLayoutMode = (type, mode) => ({type,mode,
});
action(layout/actionTypes.js)
const SINGLE_COLUMN = "SINGLECOLUMN";
const TWO_COLUMN = "TWO_COLUMN";
const TWO_FLANKS = "TWO_FLANKS";
const FULL_SCREEN = "FULLSCREEN"
export { SINGLE_COLUMN, TWO_COLUMN, TWO_FLANKS, FULL_SCREEN };