All Projects → woow-wu7 → 7-react-admin-ts

woow-wu7 / 7-react-admin-ts

Licence: MIT license
用 ts + react-hooks 实现的管理后台

Programming Languages

javascript
184084 projects - #8 most used programming language
typescript
32286 projects
CSS
56736 projects
Less
1899 projects
SCSS
7915 projects
HTML
75241 projects

Projects that are alternatives of or similar to 7-react-admin-ts

dva-typescript-antd-starter-kit
A admin dashboard application demo based on antd by typescript and dva
Stars: ✭ 61 (+165.22%)
Mutual labels:  stylelint, eslint, antd
Ant Admin
基于 antd 的后台管理平台, 在 react 中玩转 D3.js
Stars: ✭ 455 (+1878.26%)
Mutual labels:  admin, antd, echarts
react-admin-nest
React和Ant Design和 Nest.js 和 Mysql 构建的后台通用管理系统。持续更新。
Stars: ✭ 123 (+434.78%)
Mutual labels:  admin, antd, react-hooks
promotion-web
基于React: v18.x.x/Webpack: v5.x.x/React Router v6.x.x/ Antd: v5..x.x/Fetch Api/ Typescript: v4.x.x 等最新版本进行构建...
Stars: ✭ 374 (+1526.09%)
Mutual labels:  stylelint, antd, react-hooks
Static Site Boilerplate
A better workflow for building modern static websites.
Stars: ✭ 1,633 (+7000%)
Mutual labels:  stylelint, eslint
Lint Staged
🚫💩 — Run linters on git staged files
Stars: ✭ 9,492 (+41169.57%)
Mutual labels:  stylelint, eslint
Barebones
A barebones boilerplate for getting started on a bespoke front end.
Stars: ✭ 127 (+452.17%)
Mutual labels:  stylelint, eslint
electron-vue-boilerplate
Simple boilerplate for building Vue app with Electron and Webpack.
Stars: ✭ 53 (+130.43%)
Mutual labels:  stylelint, eslint
React Ssr Starter
All have been introduced React environment
Stars: ✭ 20 (-13.04%)
Mutual labels:  stylelint, eslint
Express Webpack React Redux Typescript Boilerplate
🎉 A full-stack boilerplate that using express with webpack, react and typescirpt!
Stars: ✭ 156 (+578.26%)
Mutual labels:  stylelint, eslint
eslint-config-ns
ESLint config ready to be used in multiple projects. Based on Airbnb's code style with prettier, jest and react support.
Stars: ✭ 27 (+17.39%)
Mutual labels:  stylelint, react-hooks
element-plus-admin
基于vite+ts+elementPlus
Stars: ✭ 361 (+1469.57%)
Mutual labels:  stylelint, admin
Bathe
The simplest WordPress starter theme including full setup for Sass, PostCSS, Autoprefixer, stylelint, Webpack, Eslint, imagemin, Browsersync, etc.
Stars: ✭ 65 (+182.61%)
Mutual labels:  stylelint, eslint
Frasco
Quick starter for Jekyll including full setup for Sass, PostCSS, Autoprefixer, stylelint, Webpack, ESLint, imagemin, Browsersync, etc.
Stars: ✭ 123 (+434.78%)
Mutual labels:  stylelint, eslint
Generator Dhboilerplate
Boilerplate made by David Hellmann
Stars: ✭ 54 (+134.78%)
Mutual labels:  stylelint, eslint
Front End Guide
📚 Study guide and introduction to the modern front end stack.
Stars: ✭ 14,073 (+61086.96%)
Mutual labels:  stylelint, eslint
laravel-react-boilerplate
Laravel React Boilerplate with Ant Design, Route-Level Code Splitting, Redux, Sanctum Auth
Stars: ✭ 49 (+113.04%)
Mutual labels:  antd, react-hooks
vue-admin-work
🎉🎉🚀🚀🚀🚀vue-admin-work是一个中后台系统管理方案。使用 vue2.x 及周边全家桶工具开发而来。支持多种功能,不同角色权限🚀🚀🚀🎉🎉
Stars: ✭ 74 (+221.74%)
Mutual labels:  admin, echarts
frontend-tutorial
🎨 一个后端程序员的前端技术总结
Stars: ✭ 122 (+430.43%)
Mutual labels:  eslint, antd
React 2048 Game
🎮 A fancy 2048 game build with react, redux best practices.
Stars: ✭ 401 (+1643.48%)
Mutual labels:  stylelint, eslint

7-react-admin-java

7-react-admin-java-pro

(一) 技术栈

ts + react-hooks + [email protected] + redux@^4.0.5 + react-redux + axios

husky + lint-staged + commitlint + eslint + stylelint + prettier + EditorConfig

styled-components + echarts + antd

redux-logger + redux-thunk 中间件

通过 create-react-app 脚手架构建

本项目构建过程记录博客

(二) 主要功能

(1) 功能
    - router menu breadcrumb 三合一
    - 自定义hooks ( useFetch, useModal, useViewprot, useIntersectionObserver, useThrottle, useDebounce等)
    - 自定义redux, 懒加载, 权限控制, 回到顶部, echarts封装, react-redux-hooks-api, react-router-hooks-api
    - alias别名, 全局sass, 新手功能引导动画(react-joyride)(reactour), 瀑布流, axios取消请求
    - webpack-bundle-analyzer 包分析插件
(2) css特效
    - stickyFooter粘性页脚, ceiling吸顶效果, shockWave冲击波, 水平垂直居中, 两栏三栏布局
    - rem响应布局, em, @media媒体查询, 一物理像素边框, 盒模型, 三角形, 进度条, margin重叠
    - inline-block间隙, 两行三行省略号, 多列等高布局, 滑动菜单slide-menu
(3) 源码分析
    - redux axios webpack-Compiler
    - 具体在本项目 src/SOURCE-CODE-ANALYSIS 文件夹中

(三) 源码分析

(1) redux 和 react-redux 源码分析 [redux^4.0.5]

(2) 手写 webpack Compiler 源码 [webpack^4.42.0]

(3) axios 源码分析 [axios^0.20.0]

(4) vue 源码分析 [vue^2.6.12]

(5) vuex 源码分析 [v2.6.10]

(6) react 源码分析 [react^17.0.3]

(7) a-hooks 源码分析 [a-hooks^2.10.9]

(8) a-hooks 源码分析 [a-hooks^3.1.9]

(9) koa 源码分析 [koa^2.13.1]

(10) badJs-report 源码分析

(11) element-ui 源码分析 [element-ui^2]

(12) vant [vant^3.4.5]

(13) Diff-virtualDOM

(四) 复习资料

(五) 代码规范相关 ( 1-9 )

  • 123456789

安装 husky + lint-staged + commitlint + eslint + stylelint + prettier + EditorConfig

(1) EditorConfig

  • EditorConfig官网
  • EditorConfig教程
  • 作用
    • EditorConfig 可以帮助开发者在不同的编辑器和IDE之间定义和维护一致的代码风格
  • 重点规则
    • [*] 表示用于所有文件的规则
    • [.md] 表示用于.md文件的规则
    • indent_style=space 表示当键下tab键时使用软选项卡填充缩进,也就是使用 ( 空格 ) 填充
    • indent_style=tab 表示键下tab键时使用硬选项卡填充缩进,也就是使用 ( \t ) 填充
    • indent_size=2 表示两个空格
    • trim_trailing_whitespace=true 表示将换行符前面的空格删除掉 trim: 修剪 trailing: 尾部
    • insert_final_newline=true 确保文件保存的时候以换行符结尾,即文件末尾会多一行空行
  • 配置步骤
    • 1.在vscode中下载 EditorConfig for VSCode 插件,该插件在保存时会执行.editorconfig中指定的规则
    • 2.新建 .editorconfig 文件
root=true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

(2) husky + lint-staged

  • husky官网
  • lint-staged官网
  • 教程
  • 配置步骤
    • 1.安装npm install -D husky lint-staged
    • 2.在 package.json 文件中配置 huskylint-staged 配置项
    • 3.如果在 husky => hooks => pre-commit中用到eslint,就需要配置.eslintrc.js.eslintignore不然会报错
    • 4.在配置中就用到了几乎所有代码规范的配置 husky + lint-staged + commitlint + eslint + styleslnt + prettier
  • package.json配置如下
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  },
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": [
      "eslint --config .eslintrc.js --fix"
    ],
    "*.{css,less}": [
      "stylelint --config .stylelintrc.js --fix"
    ],
    "*.{ts,tsx,js,jsx,css,less}": "prettier --write --ignore-unknown"
  }

(3) commitlint

  • commitlint官网
  • 配置步骤
    • 1.安装npm install --save-dev @commitlint/config-conventional @commitlint/cli
    • 2.安装npm install --save-dev husky
    • 3.新建.huskyrc文件或者在package.json中配置husky选项
    • 4.新建 .commitlintrc.js 注意是js文件,不能是ts,或者.commitlintrc.json等
    • 5.在.commitlintrc.js中添加扩展@commitlint/config-conventional // conventional: 传统的
在 .commitlintrc.js 中配置如下

module.exports = {
  extends: ['@commitlint/config-conventional']
};

(4) eslint

(1) 安装
- npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin

(2) 新建 .eslintrc.js 和 .eslintignore 两个文件

(3) 配置 .eslintrc.js 文件
module.exports = {
  parser: "@typescript-eslint/parser",
  extends: ["react-app", "plugin:@typescript-eslint/recommended"],
  plugins: ["@typescript-eslint", "react"],
  rules: {
    "no-console": 0,
    "@typescript-eslint/no-empty-function": 0,
    "@typescript-eslint/no-explicit-any": 0,
    "no-use-before-define": 0,
    "@typescript-eslint/explicit-module-boundary-types": 0,
    "react-hooks/exhaustive-deps": 0,
  },
};

  • 自动配置步骤
(1) 安装 npm install -D eslint

(2) 在项目根目录中,执行命令 npx eslint --init

(3) 执行2的命令后,会进入交互式界面,可根据上面的 [教程1] 进行配置,这个过程可能安装依赖时会报错,不行就自行安装依赖吧

(4) 经过23后,就会自动生成 .eslintrc.js 文件,并且配置好了

(5) stylelint

  • stylelint官网
  • 配置步骤
    • 1.npm install --save-dev stylelint stylelint-config-standard
    • 2.npm install -D stylelint-scss stylelint-webpack-plugin
    • 3.新建.stylelintrc.js
    • 4.然后添加到 huskyhooks
  • package.json 配置如下
"husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  },
  "lint-staged": {
    "*.{ts,tsx,js}": [
      "eslint --config .eslintrc.js --fix"
    ],
    "*.{css,sass,scss}": [
      "stylelint --config .stylelintrc.js --fix",
      "git add"
    ]
  }

(6) prettier

  • prettier官网
  • prettier教程
  • 配置步骤
    • 1.npm i -D prettier eslint-config-prettier eslint-plugin-prettier
    • 2.新建 .prettierrc.js 文件
    • 3.同时修改 .eslintrc.js 中的配置
  • .prettierrc.js配置如下
module.exports = {
  printWidth: 120, //一行的字符数,如果超过会进行换行,默认为80
  tabWidth: 2, //一个tab代表几个空格数,默认为2
  singleQuote: true,
  semi: false,
}
  • .eslintrc.js配置如下
module.exports = {
  parser: '@typescript-eslint/parser',
  extends: [
    'react-app',
    'plugin:@typescript-eslint/recommended',
    //  "plugin:prettier/recommended" 暂不开启
  ],
  plugins: ['@typescript-eslint', 'react', 'prettier'],
  rules: {
    'no-console': 0,
    '@typescript-eslint/no-empty-function': 0,
    '@typescript-eslint/no-explicit-any': 0,
    'no-use-before-define': 0,
    '@typescript-eslint/explicit-module-boundary-types': 0,
    'react-hooks/exhaustive-deps': 0,
  },
}

(7) git提交规范

  • 文档
  • feat: 新功能 feature
  • fix: 修复bug
  • chore:构建过程 或 辅助工具的变动 (chore:日常事务,乏味无趣的工作的意思)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • perf: 性能优化
  • docs: 文档 documentation
  • test:测试
  • style:格式(不影响代码运行的变动)

(8) js注释规范

(9) react-hooks 的 eslint 规范插件

(六) 按需加载相关

(1) react-router-dom

  • npm install react-router-dom
  • npm install @types/react-router-dom
  • 集中式路由插件 ( react-router-config )
    • npm install --save react-router-config
    • npm install @types/react-router-config -S
    • 官网
    • 使用教程
    • renderRoutes
  • react-router-dom中的hooks
    • useHistory
    • useLocation
    • useParams
      • useParams只有在动态路由对应的组件中可以获取到,在父组件或者其他组件都不能后去到
      • 做全局 面包屑的时候容易采坑
    • useRouteMatch
  • 路由按需加载

(2) antd 按需加载

  • babel-plugin-import官网
  • 实例教程
  • npm install babel-plugin-import -D
  • 配置 .babelrc 文件
    • 注意需要 eject 后修改 webpack.config.js 中的 babelrc: true 启用 .babelrc 文件
    • 同时需要删除在 package.json 中定义的 babel 选项
.babelrc
-----
{
  "presets": ["react-app"],
  "plugins": [
    [ "import", { "libraryName": "antd", "style": "css"} ]
  ]
}

(3) antd使用iconfont自定义图标

  • 官网
  • scriptUrl 就是 Symbol在线生成的文件路径

(4) redux 相关

  • npm install redux react-redux -S
  • npm install @types/react-redux -S
  • npm install --save redux-devtools-extension
  • npm install redux-devtools -D

(七) create-react-app 相关设置

(1) 添加别名 @ 映射 src 在TS的项目中

    1. create-react-app构建的项目,eject后,找到 config/webpack.config.js => resolve.alias
    1. tsconfig.json 中删除 baseUrlpaths,添加 "extends": "./paths.json"
    1. 在根目录新建 paths.json 文件,写入 baseUrlpaths 配置
  • 教程地址
1. webpack.config.js => resolve => alias
module.export = {
   resolve: {
     alias: {
      "@": path.resolve(__dirname, '../src')
     }
   }
 }
2. 根目录新建 paths.json 写入以下配置
{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@/*": ["*"]
    }
  }
}
3. 在 tsconfig.json 中做如下修改,添加( extends ), 删除(  baseUrl,paths )
{
  // "baseUrl": "src",
  // "paths": {
  //   "@/*": ["src/*"]
  // },
  "extends": "./paths.json"
}

(1.2) 遇到问题

  • 问题:当在webpack配置了别名后,ts报错找不到模块,同时vscode点击时不跳转
  • 回答:
    • paths:因为webpack知道了别名路径,但是ts并不知道这是设置了别名,所以需要设置tsconfig.json文件中的 paths
    • baseUrl: 当设置了 paths时,就必须设置baseUrl
  • 如下配置后,ts不再报错,并且vscode中点击也可以跳转
{
  "compilerOptions": {
    "baseUrl": ".", // this must be specified if "paths" is specified.当指定paths的时候,就必须指定baseUrl
    "paths": {
      "jquery": ["node_modules/jquery/dist/jquery"] // this mapping is relative to "baseUrl" 该映射是相对于 baseUrl 的
      "@/*": "src/*"
    }
  }
}

官网说明:https://www.typescriptlang.org/tsconfig#paths

(2) create-react-app 配置全局的 scss ,而不需要每次 @import

  • 安装 sass-resources-loader
  • 修改 config/webpack.config.js 如下
  • 注意:很多教程修改use:getStyleLoaders().concat()这样修改不行
const getStyleLoaders = (cssOptions, preProcessor) => {
  const loaders = [......].filter(Boolean);
  if (preProcessor) {
    loaders.push(......);
  }
  if (preProcessor === 'sass-loader') {
    loaders.push({
      loader: 'sass-resources-loader',
      options: {
          resources: [
            // 这里按照你的文件路径填写../../../ 定位到根目录下, 可以引入多个文件
            path.resolve(__dirname, '../src/style/index.scss'),
          ]
      }
    })
  }
  return loaders;
};

(2-2) create-react-app 配置全局 less

  • 安装 style-resources-loader
  • cnpm i style-resources-loader
  • github仓库
  // common function to get style loaders
  const getStyleLoaders = (cssOptions, preProcessor) => {
    const loaders = [
      ...
    ].filter(Boolean);
    if (preProcessor) {
      loaders.push(
        {
          loader: require.resolve('resolve-url-loader'),
          options: {
            sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
            root: paths.appSrc,
          },
        },
        {
          loader: require.resolve(preProcessor),
          options: {
            sourceMap: true,
          },
        }
      );
    }
    if (preProcessor === 'less-loader') {
      loaders.push({
        loader: 'style-resources-loader',
        options: {
          patterns: path.resolve(__dirname, '../src/styles/*.less'),
          injector: 'append'
        }
      })
    }
    return loaders;
  };

(3) css-module

  • 需要安装 node-sass
  • npm install node-sass -D
  • xxxx.module.scss

(4) 在 create-react-app 实现代码分割

(5) 使用TS中的 enum 枚举类型避免魔法字符串

  • export enum SYSTEMTYPE { ADMIN, BIGSCREEN }
  • import { SYSTEMTYPE } from 'src/global/enum.ts'
  • 注意点1:
    • 问题:元素隐式具有 "any" 类型,因为类型为 "string" 的表达式不能用于索引类型 "typeof SYSTEMTYPE"。
    • 解决方案:在tsconfig.json => compilerOptions => "suppressImplicitAnyIndexErrors": true,
  • 注意点2:
export enum SYSTEMTYPE1 {
  ADMIN = 'ADMIN',
  BIGSCREEN = 'BIGSCREEN',
}

export enum SYSTEMTYPE2 {
  ADMIN,
  BIGSCREEN,
}


SYSTEMTYPE1.ADMIN =========> 'ADMIN'
SYSTEMTYPE2.ADMIN =========> 0

(6) require.context => ts报错不存在属性

  • npm install @tyeps/webpack-env -D
  • require.context(direactory, useSubdirectorys, regExp, mode)
  • 作用
    • 创建自己的context
  • 参数
    • directory: 需要搜多的文件夹
    • useSubdirectory: 是否搜索其子目录
    • regExp: 匹配文件的正则表达式
    • mode:模式,比如 'sync'

(7) require.context() 实现自动化 import 功能

  • require.context(directory, useSubdirectories, regExp, mode)
  • 作用
    • 创建自己的 context
  • 参数
    • directory:需要搜索的文件夹
    • useSubdirectories:是否搜索其子目录
    • regExp:匹配文件的正则表达式
    • mode:模式,比如 'sync'
  • 返回值
    • context导出的 require() 函数
  • require() 函数
    • 参数:request
    • 属性
      • resolve函数,它返回request被解析后得到的 ( 模块id ),可能在 module.hot.accept 时会用到
      • keys函数,它返回一个数组,由所有可能被此 context module 处理的请求组成
  • require.context()本项目使用到的案例
    • 详见 requireModules 函数

(1) 获取模块的路径
const moduleContext = require.context('./Knowledge', true, /index.tsx/, 'sync')
moduleContext.keys().forEach(modulePath => {
  console.log('modulePath就是模块的路径')
})


(2) 获取模块的源码
const moduleContext = require.context('./Knowledge', true, /index.tsx/, 'sync')
moduleContext.keys().forEach(modulePath => {
  const moduleSourceCode = moduleContext(modulePath).default
  console.log('moduleSourceCode就是模块的(组件)源码')
})

(8) console.log('123 %c abc', 'font-size: 30px; color: red;')

(9) 环境变量

  • NODE_ENV
    • 运行cnpm run start时, NODE_ENV = 'development'
    • 运行cnpm run test时,NODE_ENV = 'test'
    • 运行cnpm run build时,NODE_ENV = 'production'
    • 获取:process.env.NODE_ENV
    • 注意:你无法手动覆盖 NODE_ENV
  • 在 ( .env ) 中添加开发环境变量
    • 要定义( 永久环境变量 ),请在项目的 ( 根目录 ) 创建名为 ( .env ) 的文件
    • 必须以 REACT_APP_ 开头来创建自定义环境变量,除了 ( NODE_ENV ) 之外的任何其他变量都将被忽略
    • 此功能需要在 [email protected]及更高版本
  • 除了 .env 文件,还可以用哪些命名?
    • .env:默认
    • .env.local:本地覆盖。除 test 之外的所有环境都加载此文件
    • .env.development, .env.test, .env.production:设置特定环境
    • .env.development.local, .env.test.local, .env.production.local:设置特定环境的本地覆盖
    • 注意: ( .env.development.local ) 文件会覆盖掉 ( .env.development ) 中设置的环境便变量,但不会影响 ( NODE_ENV )
    • 注意:.env.development.local文件不被识别,git push 时并不会提交,其实也没有必要使用local文件

(八) 大屏

(1) screenfull

  • 安装:cnpm install screenfull -S
  • 官网

(2) echarts封装

(3) 大屏线上项目

(4) 大屏滚动效果

(九) BUG总结

(1) 登陆页面出现的bug

  • 问题描述:登陆页面,选择系统时,报错,并且select每change一次,动画就渲染一次
  • 报错描述:Warning: Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.
  • 原因分析:
    • Select的value值,直接从redux全局state中取数据,change后又把改变的数据传入store
    • 因为是全局顶层store,导致基本整个项目根组件都重新渲染了
  • 解决办法:
      1. 可以获取store的state,在传给组件的state,然后change Select时,修改组件自己的state,只影响该组件,然后点击登陆时,在把数据传递给redux

(2) [ts]未终止的正则表达式文字

  • 注意如果有组件或者jsx返回的DOM,就必须用 tsx 文件后缀

(3) 找不到模块“xxxx”或其相应的类型声明。

  • 最简单的修复方式:在import前面加上 // @ts-ignore
  • 合理的解决办法:
    • 1、 项目根目录下添加 index.d.ts, 并在其中写类型声明

    • 2、 将 index.d.ts 加入到 tsconfig.json 中的配置项 include

      1. 创建一个 types 目录,专门用来管理自己写的声明文件,将 foo 的声明文件放到 types/foo/index.d.ts 中
      1. tsconfig.json 中的 paths 和 baseUrl 字段
    根目录/types/redux/index.d.ts
    declare module 'redux' {
      const bindActionCreators: any
      export { bindActionCreators }
    }
    
    tsconfig.json
    "compilerOptions": {
      "baseUrl": "./",
      "paths": {
        "*": [
          "types/*"
        ]
      }
    },
    
  • issue
  • ts类型声明文件的正确使用姿势

(4) style-lint

  • :global 报错
  • 解决方法:
    • .stylelintrc.js 中做以下修改
rules: {
    "selector-pseudo-class-no-unknown": [true, {
      ignorePseudoClasses: ["global"],
    }]
  },

(5) 依赖没有锁版本造成的报错

  • 报错:TypeScript error in /@pretty-format/build/index.d.ts(7,13): '=' expected. TS1005
  • 原因:"typescript": "~3.7.2", 版本问题
  • 解决:"typescript": "^3.8.2"
  • 资料:https://www.jianshu.com/p/a69ff39a91c5

(6) antdMenu Sider inlineCollapsed 报错

  • Warning: [antd: Menu] inlineCollapsed not control Menu under Sider. Should set collapsed on Sider instead.
  • mene的inlineCollapsed在有Sider父组件时,不能操作Sider,必须用Sider的collapsed属性来操作Silder展开/收缩

(7) echarts初始化时超出容器的宽度

  • 问题:当初始化时,div按照样式设置了50%的大小,但是echarts图标超出了容器大小
  • 解决:
    • 把 init设置成async函数,当实例存在的时候,再去设置setOption
    • 即确保在setOption时,echarts实例存在并且,如果实例存在,通过echarts.getInstanceByDom()直接复用,不用重新生成

(8) antd - BackTop组件不生效

  • 原因:因为antd的布局组件 Content 是不能直接设置宽高和overflow等属性
  • 解决:
    • Content 组件内部在设置容器 scrollOuterWrap 在包裹住 scrollInnterWrap,由scrollInnterWrap 包裹需要滚动的元素
    • .scrollOuterWrap:需要设置固定的高度,通过 calc 计算得到;和其他 overflow-y 相关的属性
    • antd的 BackTop 组件的层级,在哪里的层级都可以

(9) 前端部署到服务器后,刷新404

原因:因为web单页应用,其实就一个index.html页面,跳转路由只是更新页面的一部分,而不存在真正的路由对应的页面,刷新访问的地址页面是不存在的,所以要重新重定向到index.html 解决:配置nginx的try_files 具体:try_files $uri $uri/ /index.html 说明:

  • try_files:依次尝试访问对应的资源,第一个访问不到,就访问第二个资源,一次往后
  • $uri:表示Nginx地址变量,即当前的rul地址
  • $rui/:表示一个目录,nginx会自动识别是目录还是文件
server {
	listen 80;
	server_name localhost;
	location / {
		root /usr/share/nginx/html;
		index index.html index.htm;
		try_files $uri $uri/  /index.html;
	}
}

表示:当 $uri 和 $uri/ 均不是对应资源时,返回 /index.html 资源

(10) 本地开发环境用express的proxy做的代理,部署到服务器后需要用nginx做代理

  • 遇到问题:部署后前端代码是跑在 nginx 中的,代理要用nginx来做,同时因为单页应用需要做try_files来解决刷新问题
  • 解决:在前端的请求path中加入 /api,在nginx中对 /api做反向代理
server {
	listen 80;
	server_name localhost;
	location / {
		root /usr/share/nginx/html;
		index index.html index.htm;
		try_files $uri $uri/  /index.html;
	}

	location /api {
		proxy_pass  http://49.233.215.163:7001; // 因为egg启动的是7001端口
	}
}

(11) React.lazy(() => import())

  • React.lazy(() => import(/* webpackChunkName: "[request]" */, @/pages/${path}))
  • 上面的 request 就是 path 变量的值
  • 比如:path=aaa => request=aaa => 按需加载的chunk包名就包含aaa.chunk.js
  • ( React.lazy ) 需要配合 ( Suspense ) 组件
  • suspense:是悬念的意思
import React, { Suspense } from 'react'
import { Route, Switch } from 'react-router-dom'
import { lazyLoad } from '@/utils'
// 基础路由
const Login = lazyLoad('@/pages/login')
const NotFound = lazyLoad('@/pages/404')
const Layout = lazyLoad('@/pages/layout')

// renderRoutes 中包含 Switch 组件
const Router = () => {
  return (
    <Suspense fallback={<div>loading...</div>}>
      <Switch>
        <Route path='/login' render={props => { console.log("login路由"); return <Login {...props} />}} />
        <Route path='/404' render={props => { console.log("NotFount路由"); return <NotFound {...props} />}}  />
        <Route component={Layout} />
      </Switch>
    </Suspense>
  )
}

export default Router

(12) 当 eject 后报错

  • 原因:eject后,如果之前有安装依赖,就都会消失,也不会在package.json中有记录
  • 解决:
      1. 删除 node_modules 文件夹
      1. npm run eject 后需要 npm install 安装依赖,因为弹出了很多其他的依赖并没有安装
      1. 需要从新安装eject之前你安装的依赖

(13) 记录一个因为不小心而踩的深坑 - ( 关于变量和引用 )

// 根据权限对(menu),和(router注册)进行过滤
function routesFilter(routes, role) {
  return routes.filter((route) => {
    let { meta, subs } = route;
    if (subs) {
      route.subs = routesFilter(subs, role);
      // 坑:这里有个巨坑,这里一定要用route.subs
      // 例如: subs = routesFilter(subs, role);
      // 说明:不能用 subs, 因为subs是新声明的变量,直接替换了整个subs后,不会影响route.subs
    }
    return !meta.needLoginAuth || meta.rolesAuth.includes(role);
  });
}

(14) 关于菜单的 openkeys selectedKeys collapsed

  • 问题记录
  • 问题:当菜单中有展开和选中的项时,点击向左缩窄菜单时,再次向右展开,状态没有保存
  • 解决:可以通过 onOpenChange 中的 openKeys 来做持久化
    • 刚刚点击的 openKeys 存在,就使用,不存在,就使用 localStorage 中的
  • 新问题:
    • 1.这样在缩窄的菜单中hover一些之后,展开状态也变了,因为缩窄的菜单hover时也会触发openchange
    • 2.有选中和展开状态时去缩窄菜单,会有选中的菜单突出,影响观感
  // 展开/关闭的回调
  const onOpenChange = (openKeys: any) => {
    console.log(openKeys, 'onOpenChange执行了')
    setOpenKeys(() => openKeys)
    setLocalStorage(CONST.OPENKEYS, openKeys) // 记住展开关闭的组,刷新持久化
  }

  // const onOpenChange = (openKeys: any) => {
  //   console.log(openKeys, 'onOpenChange执行了')
  //   const currentopenKeys = openKeys.length
  //     ? openKeys
  //     : getLocalStorage(CONST.OPENKEYS)
  //   setLocalStorage(CONST.OPENKEYS, currentopenKeys) // 记住展开关闭的组,刷新持久化
  //   setOpenKeys(() => currentopenKeys)
  // }

(15) useDebounce

  • 问题:当 UseDebounce 组件中有其他 state 更新时,useDebounce是新的函数重新执行了,timer又会被重新赋值为初始值,造成错乱,不能达到debounce效果
  • 如何验证:useDebounce在UseDebounce组件有其他state更新时重新执行了:在useDebounce中 console.log() 打印即可
  • 如何解决:使用 useRef 固定数据,类似class中的实例变量
import { useRef } from "react";

interface IuseDebounce {
  (fn: Ifn, delay?: number, immediate?: boolean): IClosure;
}

interface Ifn {
  (...rest: any[]): any;
}

interface IClosure {
  (e: any, ...rest: any[]): any;
}

/**
 * @desc debounce 防抖函数
 * @param {function} fn 需要执行的函数
 * @param {number} delay 延时执行的时间段
 * @param {boolean} immediate 是否立即执行
 */
export const useDebounce: IuseDebounce = (
  fn: any,
  delay = 1000,
  immediate = false
) => {
  const refTimer = useRef(0); // 相当于class中的实例属性

  return (e, ...rest) => {
    if (immediate && !refTimer.current) {
      fn.call(rest);
      refTimer.current = 1; // 除了第一次进入,后面都不会在进入该函数
      return; // 第一次不往下执行
    }
    if (refTimer.current) {
      window.clearTimeout(refTimer.current);
    }

    refTimer.current = window.setTimeout(() => {
      fn.call(rest);
    }, delay);
  };
};

// -------------------- 变量 timer 版本 --------------------
// 问题:当 UseDebounce 组件中有其他 state 更新时,useDebounce是新的函数重新执行了,timer又会被重新赋值为初始值,造成错乱,不能达到debounce效果
// 如何验证:useDebounce在UseDebounce组件有其他state更新时重新执行了:在useDebounce中 console.log() 打印即可
// 如何解决:使用 useRef 固定数据,类似class中的实例变量
// export const useDebounce: IuseDebounce = (fn: any, delay = 1000, immediate = false) => {
//   let timer = 0;
//   return (e, ...rest) => {
//     if (immediate && !timer) {
//       fn.call(rest);
//       timer = 1;
//       return;
//     }
//     if (timer) {
//       window.clearTimeout(timer);
//     }
//     timer = window.setTimeout(() => {
//       fn.call(rest);
//     }, delay);
//   };
// };

(16) react-markdown

  • 1.安装: npm install --save react-markdown
  • 2.安装: npm install -D raw-loader
  • 2.引入md文件作为source
    • 引入前需要安装的依赖:npm install -D raw-loader,配置webpack
  • 3.接下来就可以正常使用了
  • 4.教程链接:https://segmentfault.com/a/1190000020294373

(17) webpack-bundle-analyzer 使用报错

  • 原因:端口被占用,如果有别的项目中也使用到了 webpack-bundle-analyzer 时就会产生端口调用
  • 解决: 关闭其他项目的服务
  • 该项目已经在开发环境添加了 webpack-bundle-analyzer 分析

(18) 在react中如果通过create-react-app创建的项目,之后想加Typescript配置

  • 1.同过配置别名时已经做了相关配置了
  • 2.在1的基础上在 scr 文件夹中添加 global.d.ts 配置文件

(十) TS 相关

(1) tsconfig.json

  • 官网介绍
  • 顶级属性
  • 如果项目中存在 tsconfig.json 代表着这个目录是Typescript项目的 根目录
  • tsconfig.json文件中指定了编译这个项目的 ( 根文件 ) 和 ( 编译选项 )
    • 根文件
    • 编译选项

(1-1) @types, typeRoots, types

  • @types: 默认所有可见的@types包会在 编译过程中被包含进来,比如 node_modules/@type/...
  • typeRoots: 如果指定了typeRoots,则只有typeRoots下面的包才会包含进来
  • types: 只有被列举的包才会包含进来
{
  "compilerOptions": {
    "typeRoots" : ["./typings"]
  }
}
表示:这个配置文件会包含 ./typings 下面的包,而不包含 ./node_modules/@types 里面的包
{
  "compilerOptions": {
    "types" : ["node", "lodash", "express"]
  }
}
表示:
1. 这个tsconfig.json文件将仅会包含 ./node_modules/@types/node,./node_modules/@types/lodash和./node_modules/@types/express
2. /@types/。 node_modules/@types/*里面的其它包不会被引入进来

(1-2) extends

  • tsconfig.json文件可以利用 extends 属性从 另一个配置文件里继承配置
  • extends的值是一个字符串,表示继承文件的路径
  • 源文件的配置先被加载,然后被继承文件中的配置重写,如果循环引用就会报错
  • 顶级属性

(1-3) compilerOptions 编译选项

  • allowJs
    • boolean,默认值false,表示允许编译js文件
  • declaration
    • boolean,默认值false,表示生成相应的 .d.ts 文件
  • jsx
    • 表示在 .tsx 文件中支持jsx

(2) 如何编写 .d.ts

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].