从0开始分享一个React项目:React-ant-admin

项目源码: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中配置

这是最简单的方法,但只能配置一个代理。

  1. 打开React项目的package.json文件。
  2. 在文件中找到或添加"proxy"字段,并设置为目标域名地址和端口号。例如:
json 复制代码
{
  // ...其他配置
  "proxy": "http://localhost:5000"
}
  1. 保存package.json文件并重启React项目。

此时,当React项目中的请求无法找到对应的路由时,会自动转发到proxy字段指定的目标域名地址上。

方法二:使用http-proxy-middleware插件⭐⭐⭐

这种方法可以配置多个代理,更加灵活。

  1. 安装http-proxy-middleware插件:
bash 复制代码
npm install http-proxy-middleware --save
  1. 在React项目的src目录下创建一个名为setupProxy.js的文件。
  2. setupProxy.js文件中进行代理配置。例如:
javascript 复制代码
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': '' },
    })
  );

  // 可以继续添加更多的代理配置
};
  1. 保存setupProxy.js文件并重启React项目。

此时,当React项目中的请求以/api1/api2为前缀时,会分别转发到http://localhost:3001http://localhost:3002上。

注意事项

  • 在使用http-proxy-middleware插件时,确保setupProxy.js文件位于src目录下,并且文件名不能更改。
  • 在配置代理时,target字段指定的是目标服务器的地址,changeOrigin字段通常设置为true以改变源地址,pathRewrite字段用于去除请求前缀。
  • 代理配置完成后,需要重启React项目才能使配置生效。

通过以上两种方法,您可以在React项目中设置代理转发,从而解决开发环境中的跨域问题。

项目环境变量管理

env-cmd 详解

一、定义与功能

env-cmd 是一个简洁的 Node.js 程序,它允许你在执行命令时加载指定的环境文件,从而轻松管理环境变量。这个工具特别适用于开发过程中需要处理不同环境下的配置变量的场景。

二、主要特性

  1. 支持多种环境文件格式 :env-cmd 支持 .env(key=value 格式)、.env.json.env.js(JavaScript 对象或 Promise)等多种环境文件格式。
  2. 灵活的环境配置 :通过 .env-cmdrc.env-cmdrc.js 文件,你可以++定义多个环境配置++,并在运行时通过命令行参数指定要使用的环境。
  3. 与 npm 脚本集成 :env-cmd 可以直接与 npm 脚本集成,++只需在 package.jsonscripts 中调用即可++。
  4. 安全性:虽然不建议将敏感数据存储在公共仓库中,但 env-cmd 提供了方便的方式来管理和保护这些信息(例如,通过环境变量文件而非硬编码在代码中)。
  5. 扩展性 :通过 --expand-envs 选项,可以将命令行参数中的环境变量进行展开,提高可编程性。
  6. 调试友好 :++--verbose 选项可用于输出调试信息,帮助排查问题++。

三、使用方法

  1. 安装:通过 npm 或 yarn 安装 env-cmd。

    bash 复制代码
    npm install env-cmd --save-dev
    # 或者
    yarn add env-cmd --dev
  2. 创建环境变量文件 :在项目根目录下创建 .env 文件(或其他支持的文件格式),并在其中定义环境变量。

  3. 配置 npm 脚本 :在 package.jsonscripts 部分添加使用 env-cmd 的脚本命令。

    json 复制代码
    {
      "scripts": {
        "start": "env-cmd -f .env.development node index.js",
        "build": "env-cmd -f .env.production webpack --config webpack.config.js"
      }
    }
  4. 运行命令:通过 npm 脚本或直接运行 env-cmd 命令来加载环境变量并执行相应的操作。

四、高级用法

  1. 指定环境配置 :使用 -e--env 选项指定要加载的环境配置名称(如果使用了 .env-cmdrc.env-cmdrc.js 文件)。

    bash 复制代码
    env-cmd -e production node index.js
  2. 环境变量插值 :在 .env 文件中,你可以引用其他环境变量来实现环境变量插值。

    plaintext 复制代码
    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 文件应该导出一个包含多个环境配置的对象。每个环境配置都是一个键值对对象,其中键是环境变量的名称,值是环境变量的值。

javascript 复制代码
module.exports = {
  development: {
    REACT_APP_API_URL: 'http://localhost:3000/api',
    // 其他开发环境变量...
  },
  production: {
    REACT_APP_API_URL: 'https://api.example.com/api',
    // 其他生产环境变量...
  },
  // 可以定义更多环境配置...
};

三、使用方法

  1. 创建 .env-cmdrc.js 文件 :在项目根目录下创建 .env-cmdrc.js 文件,并按照上述结构定义环境配置。

  2. 运行命令 :在命令行中使用 -e--env 选项指定要加载的环境配置名称。

    bash 复制代码
    env-cmd -e development node index.js
  3. 与 npm 脚本集成 :你也可以在 package.jsonscripts 部分中集成 .env-cmdrc.js 文件的使用。

    json 复制代码
    {
      "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.lazySuspense 来实现类似的功能。以下是如何使用这两种方式来实现代码拆分的示例:

使用 React.lazy 和 Suspense

  1. 安装 React 和 React-DOM(如果你还没有安装的话):

    bash 复制代码
    bash复制代码
    
    npm install react react-dom
  2. 创建一个需要按需加载的组件 (例如 OtherComponent.js):

    jsx 复制代码
    // OtherComponent.js
    import React from 'react';
     
    const OtherComponent = () => {
      return <div>This is the Other Component!</div>;
    };
     
    export default OtherComponent;
  3. 在你的主应用中使用 React.lazySuspense

    jsx 复制代码
    // 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 的示例(注意:你可能需要先安装这个库):

  1. 安装 loadable-components

    bash 复制代码
    bash复制代码
    
    npm install @loadable/component
  2. 创建一个需要按需加载的组件 (例如 OtherComponent.js,与上面的相同)。

  3. 在你的主应用中使用 Loadable

    jsx 复制代码
    // 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.lazySuspense 提供了更简单且更直接的方式来处理动态导入和加载状态。因此,如果你正在开发一个新的React应用,建议使用 React.lazySuspense

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={
Loading
}>

{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 : 0
      return 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 };

相关推荐
AlgorithmAce2 小时前
Live2D嵌入前端页面
前端
nameofworld2 小时前
前端面试笔试(六)
前端·javascript·面试·学习方法·递归回溯
前端fighter2 小时前
js基本数据新增的Symbol到底是啥呢?
前端·javascript·面试
川石教育3 小时前
Vue前端开发子组件向父组件传参
前端·vue.js·前端开发·vue前端开发·vue组件传参
GISer_Jing4 小时前
Vue前端进阶面试题目(二)
前端·vue.js·面试
乐闻x4 小时前
Pinia 实战教程:构建高效的 Vue 3 状态管理系统
前端·javascript·vue.js
weixin_431449684 小时前
web组态软件
前端·物联网·低代码·编辑器·组态
橘子味小白菜4 小时前
el-table的树形结构后端返回的id没有唯一键怎么办
前端·vue.js
grasperp4 小时前
管家婆财贸ERP BR040.销售单明细表变更
前端框架·制造·个人开发