当前位置: 首页 > article >正文

从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"字段,并设置为目标域名地址和端口号。例如:
{
  // ...其他配置
  "proxy": "http://localhost:5000"
}
  1. 保存package.json文件并重启React项目。

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

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

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

  1. 安装http-proxy-middleware插件:
npm install http-proxy-middleware --save
  1. 在React项目的src目录下创建一个名为setupProxy.js的文件。
  2. 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': '' },
    })
  );

  // 可以继续添加更多的代理配置
};
  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。

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

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

    {
      "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 文件)。

    env-cmd -e production node index.js
    
  2. 环境变量插值:在 .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',
    // 其他生产环境变量...
  },
  // 可以定义更多环境配置...
};

三、使用方法

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

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

    env-cmd -e development node index.js
    
  3. 与 npm 脚本集成:你也可以在 package.jsonscripts 部分中集成 .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.lazySuspense 来实现类似的功能。以下是如何使用这两种方式来实现代码拆分的示例:

使用 React.lazy 和 Suspense

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

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

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

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

  3. 在你的主应用中使用 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.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 };


http://www.kler.cn/a/410302.html

相关文章:

  • Python 爬虫从入门到(不)入狱学习笔记
  • 非交换几何与黎曼ζ函数:数学中的一场革命性对话
  • 设计模式:责任链实现数据流风格的数据处理
  • HarmonyOS应用开发中的页面路由与数据传输
  • 【C++】static修饰的“静态成员函数“--静态成员在哪定义?静态成员函数的作用?
  • MySQL面试-1
  • 【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
  • 搜维尔科技:多画面显示3D系统解决方案,数据孪生可视化大屏3D展示技术
  • oracle RMAN同机迁移数据库从ASM至文件系统(同机)
  • Stable Diffusion初步见解(三):扩散模型
  • 网络安全简单入门与扫描
  • 利用Python爬虫获取商品评论:技术与实践
  • 机器学习-41-对ML的思考之从开普勒的研究过程看科学范式
  • 全面解析多种mfc140u.dll丢失的解决方法,五种方法详细解决
  • 大数据-233 离线数仓 - 留存会员 需求、创建与加载DWS 层、ADS 层 与 小结
  • 【代码pycharm】动手学深度学习v2-08 线性回归 + 基础优化算法
  • 软件工程第13章小测
  • 【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
  • Docker 的存储驱动及其优缺点
  • 超高流量多级缓存架构设计!
  • 配置Springboot+vue项目在ubuntu20.04
  • Vue实训---1-创建Vue3项目
  • docker离线安装linux部分问题整理
  • 电话机器人的未来发展前景,未来发展趋势怎么样?
  • ThingsBoard规则链节点:Azure IoT Hub 节点详解
  • ubuntu 安装 conda